summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--Documentation/ABI/testing/sysfs-class-uwb_rc-wusbhc (renamed from Documentation/ABI/testing/sysfs-class-usb_host)4
-rw-r--r--Documentation/ABI/testing/sysfs-kernel-slab109
-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/cgroups/cgroups.txt11
-rw-r--r--Documentation/debugging-via-ohci1394.txt8
-rw-r--r--Documentation/dontdiff1
-rw-r--r--Documentation/feature-removal-schedule.txt39
-rw-r--r--Documentation/filesystems/ext3.txt16
-rw-r--r--Documentation/filesystems/nfs41-server.txt9
-rw-r--r--Documentation/flexible-arrays.txt43
-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/infiniband/user_mad.txt4
-rw-r--r--Documentation/infiniband/user_verbs.txt2
-rw-r--r--Documentation/isdn/INTERFACE.CAPI83
-rw-r--r--Documentation/isdn/README.gigaset34
-rw-r--r--Documentation/kbuild/kconfig.txt3
-rw-r--r--Documentation/kernel-parameters.txt4
-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/networking/pktgen.txt8
-rw-r--r--Documentation/scsi/ChangeLog.megaraid_sas62
-rw-r--r--Documentation/scsi/hptiop.txt21
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt9
-rw-r--r--Documentation/sound/alsa/HD-Audio-Models.txt1
-rw-r--r--Documentation/vm/ksm.txt13
-rw-r--r--Documentation/vm/page-types.c304
-rw-r--r--Documentation/vm/pagemap.txt8
-rw-r--r--Documentation/vm/slqbinfo.c1047
-rw-r--r--Kbuild4
-rw-r--r--MAINTAINERS61
-rw-r--r--Makefile116
-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/socket.h2
-rw-r--r--arch/alpha/kernel/systbls.S1
-rw-r--r--arch/arm/Makefile14
-rw-r--r--arch/arm/configs/da830_omapl137_defconfig1254
-rw-r--r--arch/arm/configs/da8xx_omapl_defconfig (renamed from arch/arm/configs/da850_omapl138_defconfig)174
-rw-r--r--arch/arm/configs/davinci_all_defconfig125
-rw-r--r--arch/arm/configs/omap3_beagle_defconfig1
-rw-r--r--arch/arm/include/asm/asm-offsets.h1
-rw-r--r--arch/arm/include/asm/bitops.h6
-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/socket.h2
-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/kernel/time.c1
-rw-r--r--arch/arm/kernel/traps.c76
-rw-r--r--arch/arm/mach-bcmring/core.c4
-rw-r--r--arch/arm/mach-bcmring/include/mach/system.h2
-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.c234
-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.c18
-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.c227
-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.c302
-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.c49
-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.h2
-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.h11
-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/Kconfig44
-rw-r--r--arch/arm/mach-ep93xx/Makefile.boot9
-rw-r--r--arch/arm/mach-ep93xx/clock.c166
-rw-r--r--arch/arm/mach-ep93xx/core.c31
-rw-r--r--arch/arm/mach-ep93xx/edb93xx.c31
-rw-r--r--arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h42
-rw-r--r--arch/arm/mach-ep93xx/include/mach/gpio.h16
-rw-r--r--arch/arm/mach-ep93xx/include/mach/memory.h6
-rw-r--r--arch/arm/mach-ep93xx/include/mach/platform.h4
-rw-r--r--arch/arm/mach-ep93xx/micro9.c132
-rw-r--r--arch/arm/mach-integrator/pci_v3.c1
-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-omap2/board-rx51-peripherals.c80
-rw-r--r--arch/arm/mach-omap2/board-zoom2.c4
-rw-r--r--arch/arm/mach-omap2/clock24xx.c1
-rw-r--r--arch/arm/mach-omap2/clock34xx.c35
-rw-r--r--arch/arm/mach-omap2/clockdomain.c74
-rw-r--r--arch/arm/mach-omap2/pm-debug.c4
-rw-r--r--arch/arm/mach-omap2/pm34xx.c187
-rw-r--r--arch/arm/mach-omap2/powerdomain.c39
-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.c2
-rw-r--r--arch/arm/mach-pxa/colibri-pxa3xx.c2
-rw-r--r--arch/arm/mach-pxa/cpufreq-pxa2xx.c2
-rw-r--r--arch/arm/mach-pxa/csb726.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/zylonite.c2
-rw-r--r--arch/arm/mach-sa1100/Makefile1
-rw-r--r--arch/arm/mm/cache-v6.S20
-rw-r--r--arch/arm/mm/cache-v7.S19
-rw-r--r--arch/arm/mm/fault-armv.c9
-rw-r--r--arch/arm/mm/fault.c5
-rw-r--r--arch/arm/mm/highmem.c2
-rw-r--r--arch/arm/mm/init.c2
-rw-r--r--arch/arm/mm/mmu.c2
-rw-r--r--arch/arm/plat-omap/dma.c15
-rw-r--r--arch/arm/plat-omap/include/mach/cpu.h37
-rw-r--r--arch/arm/plat-omap/include/mach/powerdomain.h2
-rw-r--r--arch/arm/plat-omap/iovmm.c9
-rw-r--r--arch/arm/plat-omap/mcbsp.c2
-rw-r--r--arch/arm/plat-omap/sram.c3
-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/include/plat/regs-s3c2412-iis.h2
-rw-r--r--arch/arm/plat-s3c24xx/adc.c1
-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/ADI_BSD.txt41
-rw-r--r--arch/blackfin/Kconfig13
-rw-r--r--arch/blackfin/include/asm/asm-offsets.h1
-rw-r--r--arch/blackfin/include/asm/atomic.h6
-rw-r--r--arch/blackfin/include/asm/bfin-global.h26
-rw-r--r--arch/blackfin/include/asm/bfin5xx_spi.h2
-rw-r--r--arch/blackfin/include/asm/bfin_rotary.h4
-rw-r--r--arch/blackfin/include/asm/bfin_simple_timer.h6
-rw-r--r--arch/blackfin/include/asm/bitops.h6
-rw-r--r--arch/blackfin/include/asm/blackfin.h5
-rw-r--r--arch/blackfin/include/asm/bug.h6
-rw-r--r--arch/blackfin/include/asm/byteorder.h5
-rw-r--r--arch/blackfin/include/asm/cache.h9
-rw-r--r--arch/blackfin/include/asm/cacheflush.h27
-rw-r--r--arch/blackfin/include/asm/cdef_LPBlackfin.h32
-rw-r--r--arch/blackfin/include/asm/checksum.h9
-rw-r--r--arch/blackfin/include/asm/clocks.h27
-rw-r--r--arch/blackfin/include/asm/context.S27
-rw-r--r--arch/blackfin/include/asm/cplb.h27
-rw-r--r--arch/blackfin/include/asm/cplbinit.h27
-rw-r--r--arch/blackfin/include/asm/cpu.h21
-rw-r--r--arch/blackfin/include/asm/def_LPBlackfin.h36
-rw-r--r--arch/blackfin/include/asm/dma-mapping.h6
-rw-r--r--arch/blackfin/include/asm/dpmc.h6
-rw-r--r--arch/blackfin/include/asm/early_printk.h22
-rw-r--r--arch/blackfin/include/asm/elf.h6
-rw-r--r--arch/blackfin/include/asm/entry.h6
-rw-r--r--arch/blackfin/include/asm/fcntl.h6
-rw-r--r--arch/blackfin/include/asm/fixed_code.h10
-rw-r--r--arch/blackfin/include/asm/flat.h5
-rw-r--r--arch/blackfin/include/asm/gpio.h27
-rw-r--r--arch/blackfin/include/asm/hardirq.h6
-rw-r--r--arch/blackfin/include/asm/io.h6
-rw-r--r--arch/blackfin/include/asm/irq.h19
-rw-r--r--arch/blackfin/include/asm/irq_handler.h6
-rw-r--r--arch/blackfin/include/asm/l1layout.h5
-rw-r--r--arch/blackfin/include/asm/linkage.h6
-rw-r--r--arch/blackfin/include/asm/mmu.h9
-rw-r--r--arch/blackfin/include/asm/mmu_context.h27
-rw-r--r--arch/blackfin/include/asm/module.h6
-rw-r--r--arch/blackfin/include/asm/mutex.h4
-rw-r--r--arch/blackfin/include/asm/nand.h12
-rw-r--r--arch/blackfin/include/asm/page.h6
-rw-r--r--arch/blackfin/include/asm/page_offset.h9
-rw-r--r--arch/blackfin/include/asm/pda.h21
-rw-r--r--arch/blackfin/include/asm/pgtable.h12
-rw-r--r--arch/blackfin/include/asm/poll.h7
-rw-r--r--arch/blackfin/include/asm/portmux.h5
-rw-r--r--arch/blackfin/include/asm/posix_types.h6
-rw-r--r--arch/blackfin/include/asm/processor.h6
-rw-r--r--arch/blackfin/include/asm/ptrace.h6
-rw-r--r--arch/blackfin/include/asm/sections.h6
-rw-r--r--arch/blackfin/include/asm/segment.h6
-rw-r--r--arch/blackfin/include/asm/sigcontext.h6
-rw-r--r--arch/blackfin/include/asm/siginfo.h6
-rw-r--r--arch/blackfin/include/asm/smp.h21
-rw-r--r--arch/blackfin/include/asm/spinlock.h6
-rw-r--r--arch/blackfin/include/asm/spinlock_types.h6
-rw-r--r--arch/blackfin/include/asm/stat.h6
-rw-r--r--arch/blackfin/include/asm/string.h6
-rw-r--r--arch/blackfin/include/asm/swab.h6
-rw-r--r--arch/blackfin/include/asm/system.h32
-rw-r--r--arch/blackfin/include/asm/thread_info.h24
-rw-r--r--arch/blackfin/include/asm/tlb.h6
-rw-r--r--arch/blackfin/include/asm/trace.h5
-rw-r--r--arch/blackfin/include/asm/traps.h13
-rw-r--r--arch/blackfin/include/asm/uaccess.h5
-rw-r--r--arch/blackfin/include/asm/unistd.h6
-rw-r--r--arch/blackfin/kernel/asm-offsets.c27
-rw-r--r--arch/blackfin/kernel/bfin_dma_5xx.c1
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c27
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbinit.c20
-rw-r--r--arch/blackfin/kernel/cplb-mpu/cplbmgr.c19
-rw-r--r--arch/blackfin/kernel/cplb-nompu/cplbinit.c19
-rw-r--r--arch/blackfin/kernel/cplb-nompu/cplbmgr.c16
-rw-r--r--arch/blackfin/kernel/cplbinfo.c26
-rw-r--r--arch/blackfin/kernel/dma-mapping.c27
-rw-r--r--arch/blackfin/kernel/early_printk.c23
-rw-r--r--arch/blackfin/kernel/entry.S27
-rw-r--r--arch/blackfin/kernel/fixed_code.S5
-rw-r--r--arch/blackfin/kernel/flat.c18
-rw-r--r--arch/blackfin/kernel/init_task.c27
-rw-r--r--arch/blackfin/kernel/irqchip.c27
-rw-r--r--arch/blackfin/kernel/module.c27
-rw-r--r--arch/blackfin/kernel/process.c27
-rw-r--r--arch/blackfin/kernel/ptrace.c28
-rw-r--r--arch/blackfin/kernel/setup.c6
-rw-r--r--arch/blackfin/kernel/shadow_console.c2
-rw-r--r--arch/blackfin/kernel/signal.c27
-rw-r--r--arch/blackfin/kernel/sys_bfin.c41
-rw-r--r--arch/blackfin/kernel/time-ts.c10
-rw-r--r--arch/blackfin/kernel/time.c64
-rw-r--r--arch/blackfin/kernel/traps.c27
-rw-r--r--arch/blackfin/kernel/vmlinux.lds.S27
-rw-r--r--arch/blackfin/lib/ashldi3.c27
-rw-r--r--arch/blackfin/lib/ashrdi3.c27
-rw-r--r--arch/blackfin/lib/checksum.c30
-rw-r--r--arch/blackfin/lib/divsi3.S28
-rw-r--r--arch/blackfin/lib/gcclib.h27
-rw-r--r--arch/blackfin/lib/lshrdi3.c27
-rw-r--r--arch/blackfin/lib/memchr.S27
-rw-r--r--arch/blackfin/lib/memcmp.S27
-rw-r--r--arch/blackfin/lib/memcpy.S37
-rw-r--r--arch/blackfin/lib/memmove.S27
-rw-r--r--arch/blackfin/lib/memset.S27
-rw-r--r--arch/blackfin/lib/modsi3.S36
-rw-r--r--arch/blackfin/lib/muldi3.S6
-rw-r--r--arch/blackfin/lib/outs.S29
-rw-r--r--arch/blackfin/lib/smulsi3_highpart.S6
-rw-r--r--arch/blackfin/lib/udivsi3.S27
-rw-r--r--arch/blackfin/lib/umodsi3.S27
-rw-r--r--arch/blackfin/lib/umulsi3_highpart.S6
-rw-r--r--arch/blackfin/mach-bf518/boards/ezbrd.c45
-rw-r--r--arch/blackfin/mach-bf518/dma.c28
-rw-r--r--arch/blackfin/mach-bf518/include/mach/bf518.h27
-rw-r--r--arch/blackfin/mach-bf518/include/mach/bfin_serial_5xx.h29
-rw-r--r--arch/blackfin/mach-bf518/include/mach/blackfin.h29
-rw-r--r--arch/blackfin/mach-bf518/include/mach/cdefBF512.h29
-rw-r--r--arch/blackfin/mach-bf518/include/mach/cdefBF514.h29
-rw-r--r--arch/blackfin/mach-bf518/include/mach/cdefBF516.h29
-rw-r--r--arch/blackfin/mach-bf518/include/mach/cdefBF518.h70
-rw-r--r--arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h28
-rw-r--r--arch/blackfin/mach-bf518/include/mach/defBF512.h28
-rw-r--r--arch/blackfin/mach-bf518/include/mach/defBF514.h28
-rw-r--r--arch/blackfin/mach-bf518/include/mach/defBF516.h28
-rw-r--r--arch/blackfin/mach-bf518/include/mach/defBF518.h56
-rw-r--r--arch/blackfin/mach-bf518/include/mach/defBF51x_base.h28
-rw-r--r--arch/blackfin/mach-bf518/include/mach/gpio.h3
-rw-r--r--arch/blackfin/mach-bf518/include/mach/irq.h29
-rw-r--r--arch/blackfin/mach-bf518/include/mach/portmux.h6
-rw-r--r--arch/blackfin/mach-bf518/ints-priority.c27
-rw-r--r--arch/blackfin/mach-bf527/boards/cm_bf527.c61
-rw-r--r--arch/blackfin/mach-bf527/boards/ezbrd.c45
-rw-r--r--arch/blackfin/mach-bf527/boards/ezkit.c60
-rw-r--r--arch/blackfin/mach-bf527/dma.c28
-rw-r--r--arch/blackfin/mach-bf527/include/mach/bf527.h27
-rw-r--r--arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h29
-rw-r--r--arch/blackfin/mach-bf527/include/mach/blackfin.h29
-rw-r--r--arch/blackfin/mach-bf527/include/mach/cdefBF522.h29
-rw-r--r--arch/blackfin/mach-bf527/include/mach/cdefBF525.h29
-rw-r--r--arch/blackfin/mach-bf527/include/mach/cdefBF527.h29
-rw-r--r--arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h28
-rw-r--r--arch/blackfin/mach-bf527/include/mach/defBF522.h28
-rw-r--r--arch/blackfin/mach-bf527/include/mach/defBF525.h28
-rw-r--r--arch/blackfin/mach-bf527/include/mach/defBF527.h28
-rw-r--r--arch/blackfin/mach-bf527/include/mach/defBF52x_base.h28
-rw-r--r--arch/blackfin/mach-bf527/include/mach/gpio.h3
-rw-r--r--arch/blackfin/mach-bf527/include/mach/irq.h29
-rw-r--r--arch/blackfin/mach-bf527/include/mach/portmux.h6
-rw-r--r--arch/blackfin/mach-bf527/ints-priority.c27
-rw-r--r--arch/blackfin/mach-bf533/boards/H8606.c33
-rw-r--r--arch/blackfin/mach-bf533/boards/blackstamp.c29
-rw-r--r--arch/blackfin/mach-bf533/boards/cm_bf533.c45
-rw-r--r--arch/blackfin/mach-bf533/boards/ezkit.c132
-rw-r--r--arch/blackfin/mach-bf533/boards/ip0x.c37
-rw-r--r--arch/blackfin/mach-bf533/boards/stamp.c60
-rw-r--r--arch/blackfin/mach-bf533/dma.c28
-rw-r--r--arch/blackfin/mach-bf533/include/mach/bf533.h27
-rw-r--r--arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h29
-rw-r--r--arch/blackfin/mach-bf533/include/mach/blackfin.h28
-rw-r--r--arch/blackfin/mach-bf533/include/mach/cdefBF532.h28
-rw-r--r--arch/blackfin/mach-bf533/include/mach/defBF532.h44
-rw-r--r--arch/blackfin/mach-bf533/include/mach/gpio.h3
-rw-r--r--arch/blackfin/mach-bf533/include/mach/irq.h28
-rw-r--r--arch/blackfin/mach-bf533/include/mach/portmux.h6
-rw-r--r--arch/blackfin/mach-bf533/ints-priority.c27
-rw-r--r--arch/blackfin/mach-bf537/boards/cm_bf537e.c46
-rw-r--r--arch/blackfin/mach-bf537/boards/cm_bf537u.c46
-rw-r--r--arch/blackfin/mach-bf537/boards/minotaur.c6
-rw-r--r--arch/blackfin/mach-bf537/boards/pnav10.c31
-rw-r--r--arch/blackfin/mach-bf537/boards/stamp.c60
-rw-r--r--arch/blackfin/mach-bf537/boards/tcm_bf537.c46
-rw-r--r--arch/blackfin/mach-bf537/dma.c28
-rw-r--r--arch/blackfin/mach-bf537/include/mach/bf537.h27
-rw-r--r--arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h29
-rw-r--r--arch/blackfin/mach-bf537/include/mach/blackfin.h29
-rw-r--r--arch/blackfin/mach-bf537/include/mach/cdefBF534.h29
-rw-r--r--arch/blackfin/mach-bf537/include/mach/cdefBF537.h29
-rw-r--r--arch/blackfin/mach-bf537/include/mach/defBF534.h28
-rw-r--r--arch/blackfin/mach-bf537/include/mach/defBF537.h29
-rw-r--r--arch/blackfin/mach-bf537/include/mach/gpio.h3
-rw-r--r--arch/blackfin/mach-bf537/include/mach/irq.h29
-rw-r--r--arch/blackfin/mach-bf537/include/mach/portmux.h6
-rw-r--r--arch/blackfin/mach-bf537/ints-priority.c27
-rw-r--r--arch/blackfin/mach-bf538/boards/ezkit.c46
-rw-r--r--arch/blackfin/mach-bf538/dma.c28
-rw-r--r--arch/blackfin/mach-bf538/include/mach/bf538.h27
-rw-r--r--arch/blackfin/mach-bf538/include/mach/bfin_serial_5xx.h29
-rw-r--r--arch/blackfin/mach-bf538/include/mach/blackfin.h29
-rw-r--r--arch/blackfin/mach-bf538/include/mach/cdefBF538.h28
-rw-r--r--arch/blackfin/mach-bf538/include/mach/defBF539.h44
-rw-r--r--arch/blackfin/mach-bf538/include/mach/gpio.h3
-rw-r--r--arch/blackfin/mach-bf538/include/mach/irq.h29
-rw-r--r--arch/blackfin/mach-bf538/include/mach/portmux.h6
-rw-r--r--arch/blackfin/mach-bf538/ints-priority.c27
-rw-r--r--arch/blackfin/mach-bf548/boards/cm_bf548.c48
-rw-r--r--arch/blackfin/mach-bf548/boards/ezkit.c49
-rw-r--r--arch/blackfin/mach-bf548/dma.c27
-rw-r--r--arch/blackfin/mach-bf548/include/mach/bf548.h27
-rw-r--r--arch/blackfin/mach-bf548/include/mach/bf54x-lq043.h6
-rw-r--r--arch/blackfin/mach-bf548/include/mach/bf54x_keys.h6
-rw-r--r--arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h29
-rw-r--r--arch/blackfin/mach-bf548/include/mach/blackfin.h29
-rw-r--r--arch/blackfin/mach-bf548/include/mach/cdefBF542.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/cdefBF544.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/cdefBF547.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/cdefBF548.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/cdefBF549.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/defBF542.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/defBF544.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/defBF547.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/defBF548.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/defBF549.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/defBF54x_base.h28
-rw-r--r--arch/blackfin/mach-bf548/include/mach/gpio.h30
-rw-r--r--arch/blackfin/mach-bf548/include/mach/irq.h29
-rw-r--r--arch/blackfin/mach-bf548/include/mach/portmux.h6
-rw-r--r--arch/blackfin/mach-bf548/ints-priority.c27
-rw-r--r--arch/blackfin/mach-bf561/atomic.S21
-rw-r--r--arch/blackfin/mach-bf561/boards/cm_bf561.c45
-rw-r--r--arch/blackfin/mach-bf561/boards/ezkit.c44
-rw-r--r--arch/blackfin/mach-bf561/boards/tepla.c14
-rw-r--r--arch/blackfin/mach-bf561/dma.c28
-rw-r--r--arch/blackfin/mach-bf561/include/mach/bf561.h27
-rw-r--r--arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h29
-rw-r--r--arch/blackfin/mach-bf561/include/mach/blackfin.h28
-rw-r--r--arch/blackfin/mach-bf561/include/mach/cdefBF561.h28
-rw-r--r--arch/blackfin/mach-bf561/include/mach/defBF561.h29
-rw-r--r--arch/blackfin/mach-bf561/include/mach/gpio.h3
-rw-r--r--arch/blackfin/mach-bf561/include/mach/irq.h29
-rw-r--r--arch/blackfin/mach-bf561/include/mach/portmux.h6
-rw-r--r--arch/blackfin/mach-bf561/include/mach/smp.h6
-rw-r--r--arch/blackfin/mach-bf561/ints-priority.c27
-rw-r--r--arch/blackfin/mach-bf561/secondary.S24
-rw-r--r--arch/blackfin/mach-bf561/smp.c21
-rw-r--r--arch/blackfin/mach-common/arch_checks.c27
-rw-r--r--arch/blackfin/mach-common/cache-c.c2
-rw-r--r--arch/blackfin/mach-common/cache.S2
-rw-r--r--arch/blackfin/mach-common/cpufreq.c27
-rw-r--r--arch/blackfin/mach-common/entry.S32
-rw-r--r--arch/blackfin/mach-common/head.S2
-rw-r--r--arch/blackfin/mach-common/interrupt.S30
-rw-r--r--arch/blackfin/mach-common/ints-priority.c35
-rw-r--r--arch/blackfin/mach-common/irqpanic.c27
-rw-r--r--arch/blackfin/mach-common/pm.c34
-rw-r--r--arch/blackfin/mach-common/smp.c22
-rw-r--r--arch/blackfin/mm/blackfin_sram.h27
-rw-r--r--arch/blackfin/mm/init.c27
-rw-r--r--arch/blackfin/mm/isram-driver.c14
-rw-r--r--arch/blackfin/mm/sram-alloc.c27
-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/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/socket.h2
-rw-r--r--arch/ia64/include/asm/unistd.h3
-rw-r--r--arch/ia64/kernel/Makefile7
-rw-r--r--arch/ia64/kernel/entry.S1
-rw-r--r--arch/ia64/kernel/mca.c104
-rw-r--r--arch/ia64/kernel/unaligned.c6
-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/pci/pci.c18
-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/m32r/kernel/smp.c1
-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/asm-offsets.c28
-rw-r--r--arch/m68knommu/kernel/entry.S6
-rw-r--r--arch/m68knommu/kernel/ptrace.c18
-rw-r--r--arch/m68knommu/mm/init.c2
-rw-r--r--arch/m68knommu/platform/5206e/config.c1
-rw-r--r--arch/m68knommu/platform/68328/entry.S32
-rw-r--r--arch/m68knommu/platform/68360/entry.S16
-rw-r--r--arch/m68knommu/platform/coldfire/entry.S20
-rw-r--r--arch/microblaze/include/asm/asm-offsets.h1
-rw-r--r--arch/microblaze/kernel/entry.S2
-rw-r--r--arch/microblaze/kernel/hw_exception_handler.S2
-rw-r--r--arch/microblaze/kernel/process.c2
-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/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/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/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/Kconfig1
-rw-r--r--arch/parisc/include/asm/asm-offsets.h1
-rw-r--r--arch/parisc/include/asm/fixmap.h4
-rw-r--r--arch/parisc/include/asm/hardirq.h20
-rw-r--r--arch/parisc/include/asm/ptrace.h5
-rw-r--r--arch/parisc/include/asm/socket.h2
-rw-r--r--arch/parisc/include/asm/syscall.h40
-rw-r--r--arch/parisc/include/asm/thread_info.h14
-rw-r--r--arch/parisc/kernel/asm-offsets.c4
-rw-r--r--arch/parisc/kernel/entry.S21
-rw-r--r--arch/parisc/kernel/irq.c5
-rw-r--r--arch/parisc/kernel/module.c2
-rw-r--r--arch/parisc/kernel/ptrace.c42
-rw-r--r--arch/parisc/kernel/signal.c5
-rw-r--r--arch/parisc/kernel/syscall.S22
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S10
-rw-r--r--arch/parisc/mm/init.c11
-rw-r--r--arch/powerpc/include/asm/asm-offsets.h1
-rw-r--r--arch/powerpc/include/asm/firmware.h10
-rw-r--r--arch/powerpc/include/asm/socket.h2
-rw-r--r--arch/powerpc/kernel/cputable.c2
-rw-r--r--arch/powerpc/kernel/entry_64.S3
-rw-r--r--arch/powerpc/kernel/kgdb.c6
-rw-r--r--arch/powerpc/kernel/pci-common.c2
-rw-r--r--arch/powerpc/kernel/process.c10
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S1
-rw-r--r--arch/powerpc/kvm/powerpc.c5
-rw-r--r--arch/powerpc/kvm/timing.h2
-rw-r--r--arch/powerpc/mm/slb_low.S10
-rw-r--r--arch/powerpc/platforms/52xx/efika.c2
-rw-r--r--arch/powerpc/platforms/amigaone/setup.c2
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c2
-rw-r--r--arch/powerpc/platforms/chrp/setup.c2
-rw-r--r--arch/powerpc/platforms/powermac/bootx_init.c2
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c7
-rw-r--r--arch/powerpc/platforms/pseries/firmware.c3
-rw-r--r--arch/s390/Kconfig15
-rw-r--r--arch/s390/defconfig1
-rw-r--r--arch/s390/hypfs/hypfs_diag.c2
-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/delay.h7
-rw-r--r--arch/s390/include/asm/elf.h12
-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/ptrace.h4
-rw-r--r--arch/s390/include/asm/setup.h17
-rw-r--r--arch/s390/include/asm/socket.h2
-rw-r--r--arch/s390/include/asm/uaccess.h2
-rw-r--r--arch/s390/include/asm/ucontext.h15
-rw-r--r--arch/s390/kernel/compat_signal.c35
-rw-r--r--arch/s390/kernel/compat_wrapper.S2
-rw-r--r--arch/s390/kernel/ftrace.c3
-rw-r--r--arch/s390/kernel/module.c3
-rw-r--r--arch/s390/kernel/processor.c6
-rw-r--r--arch/s390/kernel/ptrace.c70
-rw-r--r--arch/s390/kernel/setup.c51
-rw-r--r--arch/s390/kernel/swsusp_asm64.S26
-rw-r--r--arch/s390/kernel/vdso.c25
-rw-r--r--arch/s390/kernel/vmlinux.lds.S1
-rw-r--r--arch/s390/kvm/Kconfig1
-rw-r--r--arch/s390/kvm/kvm-s390.c5
-rw-r--r--arch/s390/kvm/kvm-s390.h2
-rw-r--r--arch/s390/lib/delay.c27
-rw-r--r--arch/s390/lib/uaccess_mvcos.c16
-rw-r--r--arch/s390/lib/uaccess_pt.c147
-rw-r--r--arch/s390/lib/uaccess_std.c14
-rw-r--r--arch/s390/mm/fault.c380
-rw-r--r--arch/s390/mm/pgtable.c12
-rw-r--r--arch/sh/Kconfig1
-rw-r--r--arch/sh/Makefile10
-rw-r--r--arch/sh/boards/board-magicpanelr2.c2
-rw-r--r--arch/sh/boards/mach-dreamcast/setup.c2
-rw-r--r--arch/sh/boards/mach-ecovec24/setup.c63
-rw-r--r--arch/sh/boards/mach-kfr2r09/setup.c139
-rw-r--r--arch/sh/boot/compressed/misc.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/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/machvec.h2
-rw-r--r--arch/sh/include/asm/mmu.h13
-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/thread_info.h26
-rw-r--r--arch/sh/kernel/Makefile3
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S2
-rw-r--r--arch/sh/kernel/cpu/sh4a/setup-shx3.c28
-rw-r--r--arch/sh/kernel/cpu/sh5/entry.S2
-rw-r--r--arch/sh/kernel/dwarf.c220
-rw-r--r--arch/sh/kernel/entry-common.S4
-rw-r--r--arch/sh/kernel/ftrace.c183
-rw-r--r--arch/sh/kernel/head_32.S2
-rw-r--r--arch/sh/kernel/io_generic.c3
-rw-r--r--arch/sh/kernel/irq.c8
-rw-r--r--arch/sh/kernel/machine_kexec.c2
-rw-r--r--arch/sh/kernel/machvec.c3
-rw-r--r--arch/sh/kernel/module.c9
-rw-r--r--arch/sh/kernel/return_address.c54
-rw-r--r--arch/sh/kernel/setup.c6
-rw-r--r--arch/sh/kernel/sh_ksyms_32.c1
-rw-r--r--arch/sh/kernel/signal_32.c33
-rw-r--r--arch/sh/kernel/signal_64.c13
-rw-r--r--arch/sh/kernel/smp.c6
-rw-r--r--arch/sh/kernel/syscalls_64.S1
-rw-r--r--arch/sh/kernel/traps.c2
-rw-r--r--arch/sh/kernel/traps_32.c11
-rw-r--r--arch/sh/mm/Kconfig2
-rw-r--r--arch/sh/mm/Makefile3
-rw-r--r--arch/sh/mm/cache-sh4.c506
-rw-r--r--arch/sh/mm/cache-sh7705.c6
-rw-r--r--arch/sh/mm/cache.c8
-rw-r--r--arch/sh/mm/consistent.c2
-rw-r--r--arch/sh/mm/init.c8
-rw-r--r--arch/sh/mm/ioremap_32.c2
-rw-r--r--arch/sh/mm/kmap.c4
-rw-r--r--arch/sh/mm/pmb-fixed.c45
-rw-r--r--arch/sh/mm/pmb.c295
-rw-r--r--arch/sh/tools/Makefile4
-rw-r--r--arch/sh/tools/gen-mach-types2
-rw-r--r--arch/sparc/Kconfig2
-rw-r--r--arch/sparc/include/asm/asm-offsets.h1
-rw-r--r--arch/sparc/include/asm/hardirq_32.h12
-rw-r--r--arch/sparc/include/asm/irq_32.h4
-rw-r--r--arch/sparc/include/asm/pci_64.h2
-rw-r--r--arch/sparc/include/asm/pgtable_64.h4
-rw-r--r--arch/sparc/include/asm/socket.h2
-rw-r--r--arch/sparc/include/asm/unistd.h3
-rw-r--r--arch/sparc/kernel/ktlb.S8
-rw-r--r--arch/sparc/kernel/ldc.c4
-rw-r--r--arch/sparc/kernel/pci.c7
-rw-r--r--arch/sparc/kernel/perf_event.c579
-rw-r--r--arch/sparc/kernel/systbls_32.S2
-rw-r--r--arch/sparc/kernel/systbls_64.S4
-rw-r--r--arch/sparc/mm/init_64.c2
-rw-r--r--arch/sparc/oprofile/init.c1
-rw-r--r--arch/um/Makefile2
-rw-r--r--arch/um/drivers/line.c1
-rw-r--r--arch/um/drivers/port_kern.c1
-rw-r--r--arch/um/include/asm/asm-offsets.h1
-rw-r--r--arch/um/kernel/irq.c1
-rw-r--r--arch/x86/Kconfig15
-rw-r--r--arch/x86/Kconfig.cpu3
-rw-r--r--arch/x86/boot/header.S2
-rw-r--r--arch/x86/boot/version.c4
-rw-r--r--arch/x86/ia32/ia32entry.S37
-rw-r--r--arch/x86/include/asm/asm-offsets.h1
-rw-r--r--arch/x86/include/asm/kvm.h1
-rw-r--r--arch/x86/include/asm/kvm_host.h22
-rw-r--r--arch/x86/include/asm/mce.h2
-rw-r--r--arch/x86/include/asm/paravirt.h28
-rw-r--r--arch/x86/include/asm/paravirt_types.h10
-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/kernel/cpu/mcheck/mce.c58
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_intel.c1
-rw-r--r--arch/x86/kernel/cpu/mtrr/if.c17
-rw-r--r--arch/x86/kernel/e820.c4
-rw-r--r--arch/x86/kernel/early_printk.c5
-rw-r--r--arch/x86/kernel/i386_ksyms_32.c2
-rw-r--r--arch/x86/kernel/irq.c4
-rw-r--r--arch/x86/kernel/kgdb.c12
-rw-r--r--arch/x86/kernel/pci-dma.c4
-rw-r--r--arch/x86/kernel/pci-gart_64.c1
-rw-r--r--arch/x86/kernel/reboot.c3
-rw-r--r--arch/x86/kernel/syscall_table_32.S1
-rw-r--r--arch/x86/kernel/time.c3
-rw-r--r--arch/x86/kernel/trampoline.c12
-rw-r--r--arch/x86/kernel/trampoline_64.S4
-rw-r--r--arch/x86/kernel/vmi_32.c2
-rw-r--r--arch/x86/kvm/Makefile3
-rw-r--r--arch/x86/kvm/emulate.c154
-rw-r--r--arch/x86/kvm/i8254.c2
-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.c86
-rw-r--r--arch/x86/kvm/paging_tmpl.h18
-rw-r--r--arch/x86/kvm/svm.c191
-rw-r--r--arch/x86/kvm/vmx.c190
-rw-r--r--arch/x86/kvm/x86.c207
-rw-r--r--arch/x86/lib/Makefile6
-rw-r--r--arch/x86/pci/Makefile1
-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.c8
-rw-r--r--arch/x86/pci/intel_bus.c90
-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--arch/xtensa/kernel/time.c1
-rw-r--r--block/Kconfig.iosched26
-rw-r--r--block/Makefile1
-rw-r--r--block/as-iosched.c1520
-rw-r--r--block/blk-core.c16
-rw-r--r--block/blk-merge.c2
-rw-r--r--block/blk-settings.c2
-rw-r--r--block/blk-tag.c2
-rw-r--r--block/cfq-iosched.c259
-rw-r--r--block/elevator.c14
-rw-r--r--block/genhd.c4
-rw-r--r--crypto/aead.c1
-rw-r--r--drivers/accessibility/braille/braille_console.c1
-rw-r--r--drivers/acpi/Kconfig4
-rw-r--r--drivers/acpi/ac.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/button.c3
-rw-r--r--drivers/acpi/pci_root.c11
-rw-r--r--drivers/acpi/video.c7
-rw-r--r--drivers/acpi/video_detect.c2
-rw-r--r--drivers/ata/ahci.c198
-rw-r--r--drivers/ata/libata-acpi.c40
-rw-r--r--drivers/ata/libata-core.c3
-rw-r--r--drivers/ata/libata-eh.c50
-rw-r--r--drivers/ata/libata.h2
-rw-r--r--drivers/ata/pata_ali.c2
-rw-r--r--drivers/ata/pata_atp867x.c101
-rw-r--r--drivers/block/Kconfig2
-rw-r--r--drivers/block/Makefile1
-rw-r--r--drivers/block/cciss.c79
-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_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/cdrom/gdrom.c10
-rw-r--r--drivers/char/agp/parisc-agp.c2
-rw-r--r--drivers/char/applicom.c1
-rw-r--r--drivers/char/epca.c1
-rw-r--r--drivers/char/generic_serial.c1
-rw-r--r--drivers/char/genrtc.c1
-rw-r--r--drivers/char/hw_random/virtio-rng.c3
-rw-r--r--drivers/char/istallion.c1
-rw-r--r--drivers/char/nozomi.c1
-rw-r--r--drivers/char/pty.c1
-rw-r--r--drivers/char/rio/riocmd.c1
-rw-r--r--drivers/char/rio/rioctrl.c1
-rw-r--r--drivers/char/rio/riotty.c1
-rw-r--r--drivers/char/rtc.c1
-rw-r--r--drivers/char/ser_a2232.c1
-rw-r--r--drivers/char/sonypi.c1
-rw-r--r--drivers/char/stallion.c1
-rw-r--r--drivers/char/tlclk.c1
-rw-r--r--drivers/char/tpm/tpm.c3
-rw-r--r--drivers/char/tty_buffer.c31
-rw-r--r--drivers/char/virtio_console.c1
-rw-r--r--drivers/char/vt_ioctl.c2
-rw-r--r--drivers/connector/cn_proc.c3
-rw-r--r--drivers/crypto/padlock-sha.c14
-rw-r--r--drivers/edac/Kconfig14
-rw-r--r--drivers/edac/Makefile5
-rw-r--r--drivers/edac/amd64_edac.c104
-rw-r--r--drivers/edac/amd64_edac.h23
-rw-r--r--drivers/edac/amd64_edac_inj.c49
-rw-r--r--drivers/edac/edac_mce_amd.c32
-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.c48
-rw-r--r--drivers/firmware/iscsi_ibft.c2
-rw-r--r--drivers/firmware/iscsi_ibft_find.c4
-rw-r--r--drivers/gpio/adp5520-gpio.c36
-rw-r--r--drivers/gpio/wm831x-gpio.c4
-rw-r--r--drivers/gpu/drm/drm_crtc.c2
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c138
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c1
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h2
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c10
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c10
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h49
-rw-r--r--drivers/gpu/drm/i915/intel_display.c15
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
-rw-r--r--drivers/gpu/drm/i915/intel_fb.c10
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c2
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c3
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c267
-rw-r--r--drivers/gpu/drm/radeon/r100.c434
-rw-r--r--drivers/gpu/drm/radeon/r100d.h145
-rw-r--r--drivers/gpu/drm/radeon/r200.c3
-rw-r--r--drivers/gpu/drm/radeon/r300.c308
-rw-r--r--drivers/gpu/drm/radeon/r300d.h205
-rw-r--r--drivers/gpu/drm/radeon/r420.c6
-rw-r--r--drivers/gpu/drm/radeon/r420d.h24
-rw-r--r--drivers/gpu/drm/radeon/r520.c3
-rw-r--r--drivers/gpu/drm/radeon/r600.c314
-rw-r--r--drivers/gpu/drm/radeon/r600_cs.c2
-rw-r--r--drivers/gpu/drm/radeon/r600d.h1
-rw-r--r--drivers/gpu/drm/radeon/radeon.h58
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h253
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c125
-rw-r--r--drivers/gpu/drm/radeon/radeon_bios.c49
-rw-r--r--drivers/gpu/drm/radeon/radeon_clocks.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_combios.c64
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c77
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c237
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c55
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c95
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_irq_kms.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_crtc.c41
-rw-r--r--drivers/gpu/drm/radeon/radeon_legacy_encoders.c36
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h21
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c17
-rw-r--r--drivers/gpu/drm/radeon/rs100d.h40
-rw-r--r--drivers/gpu/drm/radeon/rs400.c275
-rw-r--r--drivers/gpu/drm/radeon/rs400d.h160
-rw-r--r--drivers/gpu/drm/radeon/rs600.c481
-rw-r--r--drivers/gpu/drm/radeon/rs600d.h470
-rw-r--r--drivers/gpu/drm/radeon/rs690.c355
-rw-r--r--drivers/gpu/drm/radeon/rs690d.h307
-rw-r--r--drivers/gpu/drm/radeon/rs690r.h99
-rw-r--r--drivers/gpu/drm/radeon/rv200d.h36
-rw-r--r--drivers/gpu/drm/radeon/rv250d.h123
-rw-r--r--drivers/gpu/drm/radeon/rv350d.h52
-rw-r--r--drivers/gpu/drm/radeon/rv515.c5
-rw-r--r--drivers/gpu/drm/radeon/rv770.c199
-rw-r--r--drivers/gpu/drm/ttm/ttm_global.c2
-rw-r--r--drivers/hid/hid-core.c8
-rw-r--r--drivers/hid/hid-lg.h2
-rw-r--r--drivers/hid/hid-twinhan.c4
-rw-r--r--drivers/hid/hidraw.c5
-rw-r--r--drivers/hid/usbhid/hid-core.c9
-rw-r--r--drivers/hwmon/Kconfig19
-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/asus_atk0110.c339
-rw-r--r--drivers/hwmon/dme1737.c32
-rw-r--r--drivers/hwmon/ds1621.c22
-rw-r--r--drivers/hwmon/f75375s.c31
-rw-r--r--drivers/hwmon/fschmd.c53
-rw-r--r--drivers/hwmon/gl518sm.c29
-rw-r--r--drivers/hwmon/gl520sm.c12
-rw-r--r--drivers/hwmon/lis3lv02d_spi.c3
-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/sht15.c8
-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.c4
-rw-r--r--drivers/i2c/busses/i2c-powermac.c115
-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/au1xxx-ide.c21
-rw-r--r--drivers/ide/ide-proc.c8
-rw-r--r--drivers/ide/sis5513.c10
-rw-r--r--drivers/ieee1394/raw1394.c1
-rw-r--r--drivers/ieee1394/video1394.c1
-rw-r--r--drivers/infiniband/core/addr.c2
-rw-r--r--drivers/infiniband/core/iwcm.c3
-rw-r--r--drivers/infiniband/core/ucma.c1
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c12
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_qp.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba7220.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_pages.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_sdma.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs_mcast.c1
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c12
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c2
-rw-r--r--drivers/input/input.c65
-rw-r--r--drivers/input/joystick/xpad.c2
-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.c45
-rw-r--r--drivers/input/keyboard/davinci_keyscan.c337
-rw-r--r--drivers/input/keyboard/hilkbd.c1
-rw-r--r--drivers/input/keyboard/lkkbd.c496
-rw-r--r--drivers/input/keyboard/sunkbd.c1
-rw-r--r--drivers/input/misc/rotary_encoder.c4
-rw-r--r--drivers/input/misc/sparcspkr.c4
-rw-r--r--drivers/input/misc/wistron_btns.c9
-rw-r--r--drivers/input/mouse/synaptics.c10
-rw-r--r--drivers/input/mouse/vsxxxaa.c374
-rw-r--r--drivers/input/serio/Kconfig21
-rw-r--r--drivers/input/serio/Makefile1
-rw-r--r--drivers/input/serio/altera_ps2.c200
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h2
-rw-r--r--drivers/input/serio/i8042.c3
-rw-r--r--drivers/input/serio/libps2.c1
-rw-r--r--drivers/input/serio/serio_raw.c1
-rw-r--r--drivers/input/serio/serport.c1
-rw-r--r--drivers/input/touchscreen/ad7879.c4
-rw-r--r--drivers/isdn/capi/capi.c2
-rw-r--r--drivers/isdn/capi/capidrv.c27
-rw-r--r--drivers/isdn/capi/kcapi.c1
-rw-r--r--drivers/isdn/gigaset/Kconfig25
-rw-r--r--drivers/isdn/gigaset/Makefile5
-rw-r--r--drivers/isdn/gigaset/asyncdata.c150
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c91
-rw-r--r--drivers/isdn/gigaset/capi.c2273
-rw-r--r--drivers/isdn/gigaset/common.c210
-rw-r--r--drivers/isdn/gigaset/dummyll.c68
-rw-r--r--drivers/isdn/gigaset/ev-layer.c118
-rw-r--r--drivers/isdn/gigaset/gigaset.h97
-rw-r--r--drivers/isdn/gigaset/i4l.c529
-rw-r--r--drivers/isdn/gigaset/interface.c9
-rw-r--r--drivers/isdn/gigaset/isocdata.c107
-rw-r--r--drivers/isdn/hisax/arcofi.c1
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c1
-rw-r--r--drivers/isdn/hisax/hfc_pci.c1
-rw-r--r--drivers/isdn/hysdn/hysdn_procconf.c1
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c1
-rw-r--r--drivers/isdn/mISDN/socket.c3
-rw-r--r--drivers/isdn/pcbit/drv.c1
-rw-r--r--drivers/isdn/pcbit/layer2.c1
-rw-r--r--drivers/isdn/sc/init.c1
-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-ss4200.c552
-rw-r--r--drivers/lguest/interrupts_and_traps.c1
-rw-r--r--drivers/macintosh/via-pmu.c40
-rw-r--r--drivers/md/dm-exception-store.c64
-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.c27
-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.c1
-rw-r--r--drivers/media/video/meye.c1
-rw-r--r--drivers/media/video/videobuf-core.c1
-rw-r--r--drivers/media/video/videobuf-dma-sg.c1
-rw-r--r--drivers/message/fusion/mptbase.h4
-rw-r--r--drivers/message/fusion/mptctl.c5
-rw-r--r--drivers/message/fusion/mptlan.c1
-rw-r--r--drivers/message/fusion/mptscsih.c86
-rw-r--r--drivers/mfd/Kconfig28
-rw-r--r--drivers/mfd/Makefile9
-rw-r--r--drivers/mfd/ab3100-core.c3
-rw-r--r--drivers/mfd/ab4500-core.c208
-rw-r--r--drivers/mfd/adp5520.c378
-rw-r--r--drivers/mfd/asic3.c45
-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.c91
-rw-r--r--drivers/mfd/ucb1x00-core.c1
-rw-r--r--drivers/mfd/wm831x-core.c216
-rw-r--r--drivers/mfd/wm8350-core.c769
-rw-r--r--drivers/mfd/wm8350-irq.c525
-rw-r--r--drivers/misc/Kconfig10
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/ds1682.c (renamed from drivers/i2c/chips/ds1682.c)0
-rw-r--r--drivers/misc/hpilo.c1
-rw-r--r--drivers/misc/ibmasm/command.c1
-rw-r--r--drivers/misc/ibmasm/event.c1
-rw-r--r--drivers/misc/ibmasm/r_heartbeat.c1
-rw-r--r--drivers/misc/ics932s401.c37
-rw-r--r--drivers/misc/phantom.c1
-rw-r--r--drivers/mmc/core/core.c4
-rw-r--r--drivers/mmc/core/core.h10
-rw-r--r--drivers/mmc/core/sdio_cis.c7
-rw-r--r--drivers/mmc/host/au1xmmc.c8
-rw-r--r--drivers/mmc/host/pxamci.c4
-rw-r--r--drivers/mmc/host/tmio_mmc.c78
-rw-r--r--drivers/mmc/host/tmio_mmc.h46
-rw-r--r--drivers/mtd/devices/m25p80.c8
-rw-r--r--drivers/mtd/devices/sst25l.c1
-rw-r--r--drivers/mtd/maps/Kconfig1
-rw-r--r--drivers/mtd/maps/gpio-addr-flash.c5
-rw-r--r--drivers/mtd/maps/sa1100-flash.c4
-rw-r--r--drivers/mtd/nand/Kconfig2
-rw-r--r--drivers/mtd/nand/atmel_nand.c1
-rw-r--r--drivers/mtd/nand/au1550nd.c4
-rw-r--r--drivers/mtd/nand/davinci_nand.c2
-rw-r--r--drivers/mtd/nand/nand_base.c6
-rw-r--r--drivers/mtd/nand/pxa3xx_nand.c82
-rw-r--r--drivers/mtd/onenand/onenand_base.c176
-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/Kconfig13
-rw-r--r--drivers/net/Makefile10
-rw-r--r--drivers/net/acenic.c3
-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.c4
-rw-r--r--drivers/net/bcm63xx_enet.c5
-rw-r--r--drivers/net/benet/be.h1
-rw-r--r--drivers/net/benet/be_cmds.c60
-rw-r--r--drivers/net/benet/be_cmds.h39
-rw-r--r--drivers/net/benet/be_ethtool.c45
-rw-r--r--drivers/net/benet/be_main.c16
-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_main.c77
-rw-r--r--drivers/net/bonding/bond_sysfs.c54
-rw-r--r--drivers/net/bonding/bonding.h11
-rw-r--r--drivers/net/can/Kconfig7
-rw-r--r--drivers/net/can/Makefile1
-rw-r--r--drivers/net/can/at91_can.c2
-rw-r--r--drivers/net/can/dev.c32
-rw-r--r--drivers/net/can/sja1000/sja1000.c3
-rw-r--r--drivers/net/can/sja1000/sja1000.h2
-rw-r--r--drivers/net/can/sja1000/sja1000_of_platform.c1
-rw-r--r--drivers/net/can/ti_hecc.c1002
-rw-r--r--drivers/net/can/usb/ems_usb.c4
-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.c28
-rw-r--r--drivers/net/davinci_emac.c62
-rw-r--r--drivers/net/depca.c1
-rw-r--r--drivers/net/dl2k.c18
-rw-r--r--drivers/net/e100.c6
-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/82571.c4
-rw-r--r--drivers/net/e1000e/e1000.h1
-rw-r--r--drivers/net/e1000e/ethtool.c41
-rw-r--r--drivers/net/e1000e/netdev.c80
-rw-r--r--drivers/net/ehea/ehea_main.c9
-rw-r--r--drivers/net/enic/enic_main.c15
-rw-r--r--drivers/net/eql.c1
-rw-r--r--drivers/net/ethoc.c85
-rw-r--r--drivers/net/ewrk3.c1
-rw-r--r--drivers/net/fec_mpc52xx.c6
-rw-r--r--drivers/net/fec_mpc52xx_phy.c1
-rw-r--r--drivers/net/forcedeth.c1
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c1
-rw-r--r--drivers/net/fs_enet/mii-bitbang.c1
-rw-r--r--drivers/net/fs_enet/mii-fec.c1
-rw-r--r--drivers/net/fsl_pq_mdio.c1
-rw-r--r--drivers/net/gianfar.c595
-rw-r--r--drivers/net/gianfar.h1
-rw-r--r--drivers/net/hamachi.c13
-rw-r--r--drivers/net/hamradio/baycom_epp.c7
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c1
-rw-r--r--drivers/net/hamradio/baycom_ser_hdx.c1
-rw-r--r--drivers/net/hamradio/hdlcdrv.c1
-rw-r--r--drivers/net/hp100.c1
-rw-r--r--drivers/net/ibm_newemac/core.c19
-rw-r--r--drivers/net/ibm_newemac/emac.h1
-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.c44
-rw-r--r--drivers/net/igb/igb_main.c312
-rw-r--r--drivers/net/igbvf/ethtool.c25
-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/sa1100_ir.c7
-rw-r--r--drivers/net/irda/toim3232-sir.c1
-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.c130
-rw-r--r--drivers/net/ixgbe/ixgbe_dcb_nl.c2
-rw-r--r--drivers/net/ixgbe/ixgbe_ethtool.c63
-rw-r--r--drivers/net/ixgbe/ixgbe_main.c44
-rw-r--r--drivers/net/ixgbe/ixgbe_type.h13
-rw-r--r--drivers/net/ixp2000/enp2611.c18
-rw-r--r--drivers/net/ixp2000/ixpdev.c14
-rw-r--r--drivers/net/korina.c5
-rw-r--r--drivers/net/ks8842.c5
-rw-r--r--drivers/net/lib82596.c11
-rw-r--r--drivers/net/mdio.c12
-rw-r--r--drivers/net/mlx4/main.c2
-rw-r--r--drivers/net/myri10ge/myri10ge.c5
-rw-r--r--drivers/net/netxen/netxen_nic.h25
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c2
-rw-r--r--drivers/net/netxen/netxen_nic_hdr.h69
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c788
-rw-r--r--drivers/net/netxen/netxen_nic_init.c19
-rw-r--r--drivers/net/netxen/netxen_nic_main.c226
-rw-r--r--drivers/net/niu.c7
-rw-r--r--drivers/net/ns83820.c1
-rw-r--r--drivers/net/pasemi_mac_ethtool.c17
-rw-r--r--drivers/net/pcmcia/3c574_cs.c13
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c10
-rw-r--r--drivers/net/pcnet32.c1
-rw-r--r--drivers/net/phy/mdio-gpio.c1
-rw-r--r--drivers/net/ppp_async.c5
-rw-r--r--drivers/net/ppp_synctty.c5
-rw-r--r--drivers/net/pppox.c2
-rw-r--r--drivers/net/qlge/qlge.h43
-rw-r--r--drivers/net/qlge/qlge_ethtool.c71
-rw-r--r--drivers/net/qlge/qlge_main.c168
-rw-r--r--drivers/net/qlge/qlge_mpi.c130
-rw-r--r--drivers/net/r8169.c990
-rw-r--r--drivers/net/sb1000.c1
-rw-r--r--drivers/net/sb1250-mac.c1
-rw-r--r--drivers/net/sc92031.c4
-rw-r--r--drivers/net/sfc/sfe4001.c4
-rw-r--r--drivers/net/sfc/tenxpress.c10
-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/sis900.c1
-rw-r--r--drivers/net/skfp/skfddi.c1
-rw-r--r--drivers/net/skge.c8
-rw-r--r--drivers/net/sky2.c3
-rw-r--r--drivers/net/slip.c1
-rw-r--r--drivers/net/smsc911x.c3
-rw-r--r--drivers/net/stmmac/Kconfig53
-rw-r--r--drivers/net/stmmac/Makefile4
-rw-r--r--drivers/net/stmmac/common.h330
-rw-r--r--drivers/net/stmmac/descs.h163
-rw-r--r--drivers/net/stmmac/gmac.c693
-rw-r--r--drivers/net/stmmac/gmac.h204
-rw-r--r--drivers/net/stmmac/mac100.c517
-rw-r--r--drivers/net/stmmac/mac100.h116
-rw-r--r--drivers/net/stmmac/stmmac.h98
-rw-r--r--drivers/net/stmmac/stmmac_ethtool.c395
-rw-r--r--drivers/net/stmmac/stmmac_main.c2204
-rw-r--r--drivers/net/stmmac/stmmac_mdio.c217
-rw-r--r--drivers/net/stmmac/stmmac_timer.c140
-rw-r--r--drivers/net/stmmac/stmmac_timer.h41
-rw-r--r--drivers/net/sungem.c1
-rw-r--r--drivers/net/tehuti.c27
-rw-r--r--drivers/net/tg3.c41
-rw-r--r--drivers/net/tg3.h1
-rw-r--r--drivers/net/tlan.c7
-rw-r--r--drivers/net/tokenring/ibmtr.c1
-rw-r--r--drivers/net/tsi108_eth.c10
-rw-r--r--drivers/net/tun.c5
-rw-r--r--drivers/net/typhoon.c1
-rw-r--r--drivers/net/usb/cdc_ether.c20
-rw-r--r--drivers/net/usb/pegasus.c13
-rw-r--r--drivers/net/usb/pegasus.h6
-rw-r--r--drivers/net/usb/rndis_host.c1
-rw-r--r--drivers/net/usb/usbnet.c17
-rw-r--r--drivers/net/via-rhine.c8
-rw-r--r--drivers/net/via-velocity.c3
-rw-r--r--drivers/net/virtio_net.c8
-rw-r--r--drivers/net/vmxnet3/Makefile35
-rw-r--r--drivers/net/vmxnet3/upt1_defs.h96
-rw-r--r--drivers/net/vmxnet3/vmxnet3_defs.h535
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c2565
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c566
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h389
-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/c101.c1
-rw-r--r--drivers/net/wan/cosa.c1
-rw-r--r--drivers/net/wan/cycx_x25.c1
-rw-r--r--drivers/net/wan/dscc4.c1
-rw-r--r--drivers/net/wan/farsync.c1
-rw-r--r--drivers/net/wan/hdlc_cisco.c18
-rw-r--r--drivers/net/wan/n2.c1
-rw-r--r--drivers/net/wan/pci200syn.c1
-rw-r--r--drivers/net/wireless/Kconfig84
-rw-r--r--drivers/net/wireless/adm8211.h2
-rw-r--r--drivers/net/wireless/airo.c3
-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.h4
-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.h2
-rw-r--r--drivers/net/wireless/ath/ar9170/mac.c15
-rw-r--r--drivers/net/wireless/ath/ar9170/main.c30
-rw-r--r--drivers/net/wireless/ath/ar9170/phy.c99
-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.h12
-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/b43/b43.h168
-rw-r--r--drivers/net/wireless/b43/leds.c4
-rw-r--r--drivers/net/wireless/b43/leds.h5
-rw-r--r--drivers/net/wireless/b43/main.c11
-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/xmit.c5
-rw-r--r--drivers/net/wireless/b43legacy/main.c5
-rw-r--r--drivers/net/wireless/b43legacy/phy.c1
-rw-r--r--drivers/net/wireless/hostap/Kconfig2
-rw-r--r--drivers/net/wireless/hostap/hostap_info.c1
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c1
-rw-r--r--drivers/net/wireless/ipw2x00/Kconfig7
-rw-r--r--drivers/net/wireless/ipw2x00/ipw2200.c2
-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.c40
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-hw.h6
-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-rs.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c275
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965-hw.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c160
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-5000.c223
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-6000.c268
-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.c466
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c177
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-calib.c75
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-commands.h77
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c262
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h41
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h7
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debug.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c662
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h82
-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.c68
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-eeprom.h37
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-hcmd.c22
-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.c149
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-power.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c165
-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.c63
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c255
-rw-r--r--drivers/net/wireless/iwmc3200wifi/cfg80211.c1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/commands.c1
-rw-r--r--drivers/net/wireless/iwmc3200wifi/main.c3
-rw-r--r--drivers/net/wireless/iwmc3200wifi/rx.c1
-rw-r--r--drivers/net/wireless/libertas/Kconfig39
-rw-r--r--drivers/net/wireless/libertas/Makefile15
-rw-r--r--drivers/net/wireless/libertas/README26
-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.c109
-rw-r--r--drivers/net/wireless/libertas/cmd.h5
-rw-r--r--drivers/net/wireless/libertas/cmdresp.c13
-rw-r--r--drivers/net/wireless/libertas/debugfs.c27
-rw-r--r--drivers/net/wireless/libertas/decl.h3
-rw-r--r--drivers/net/wireless/libertas/defs.h2
-rw-r--r--drivers/net/wireless/libertas/dev.h19
-rw-r--r--drivers/net/wireless/libertas/host.h1
-rw-r--r--drivers/net/wireless/libertas/if_cs.c3
-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.c3
-rw-r--r--drivers/net/wireless/libertas/if_usb.c3
-rw-r--r--drivers/net/wireless/libertas/main.c173
-rw-r--r--drivers/net/wireless/libertas/scan.c11
-rw-r--r--drivers/net/wireless/libertas/tx.c1
-rw-r--r--drivers/net/wireless/libertas/wext.c64
-rw-r--r--drivers/net/wireless/orinoco/Kconfig4
-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/prism54/isl_ioctl.c1
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c1
-rw-r--r--drivers/net/wireless/prism54/islpci_mgt.c1
-rw-r--r--drivers/net/wireless/rt2x00/rt2800usb.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00debug.c1
-rw-r--r--drivers/net/wireless/wl12xx/wl1251_main.c5
-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.c84
-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/znet.c8
-rw-r--r--drivers/oprofile/event_buffer.c35
-rw-r--r--drivers/pci/dmar.c13
-rw-r--r--drivers/pci/hotplug/cpqphp.h1
-rw-r--r--drivers/pci/intel-iommu.c82
-rw-r--r--drivers/pci/pci.c103
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c3
-rw-r--r--drivers/pci/pcie/portdrv_pci.c3
-rw-r--r--drivers/pci/quirks.c32
-rw-r--r--drivers/pci/setup-bus.c13
-rw-r--r--drivers/pci/setup-res.c37
-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/db1xxx_ss.c630
-rw-r--r--drivers/pcmcia/xxs1500_ss.c357
-rw-r--r--drivers/platform/x86/compal-laptop.c1
-rw-r--r--drivers/platform/x86/eeepc-laptop.c31
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c2
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c24
-rw-r--r--drivers/rtc/Kconfig19
-rw-r--r--drivers/rtc/Makefile2
-rw-r--r--drivers/rtc/interface.c1
-rw-r--r--drivers/rtc/rtc-dev.c1
-rw-r--r--drivers/rtc/rtc-msm6242.c268
-rw-r--r--drivers/rtc/rtc-rp5c01.c222
-rw-r--r--drivers/s390/block/dasd.c18
-rw-r--r--drivers/s390/block/dasd_diag.c19
-rw-r--r--drivers/s390/block/dasd_eckd.c13
-rw-r--r--drivers/s390/char/raw3270.c2
-rw-r--r--drivers/s390/char/sclp_async.c4
-rw-r--r--drivers/s390/char/sclp_vt220.c30
-rw-r--r--drivers/s390/char/tape_block.c3
-rw-r--r--drivers/s390/cio/blacklist.c13
-rw-r--r--drivers/s390/cio/chp.c2
-rw-r--r--drivers/s390/cio/device.c13
-rw-r--r--drivers/s390/cio/device.h1
-rw-r--r--drivers/s390/cio/device_fsm.c35
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c13
-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/scsi/zfcp_aux.c33
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c40
-rw-r--r--drivers/s390/scsi/zfcp_cfdc.c17
-rw-r--r--drivers/s390/scsi/zfcp_ext.h2
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c22
-rw-r--r--drivers/scsi/3w-xxxx.c2
-rw-r--r--drivers/scsi/Kconfig11
-rw-r--r--drivers/scsi/Makefile2
-rw-r--r--drivers/scsi/be2iscsi/Kconfig8
-rw-r--r--drivers/scsi/be2iscsi/Makefile8
-rw-r--r--drivers/scsi/be2iscsi/be.h183
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.c523
-rw-r--r--drivers/scsi/be2iscsi/be_cmds.h877
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.c638
-rw-r--r--drivers/scsi/be2iscsi/be_iscsi.h75
-rw-r--r--drivers/scsi/be2iscsi/be_main.c3390
-rw-r--r--drivers/scsi/be2iscsi/be_main.h837
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.c321
-rw-r--r--drivers/scsi/be2iscsi/be_mgmt.h249
-rw-r--r--drivers/scsi/bfa/Makefile15
-rw-r--r--drivers/scsi/bfa/bfa_callback_priv.h57
-rw-r--r--drivers/scsi/bfa/bfa_cb_ioim_macros.h205
-rw-r--r--drivers/scsi/bfa/bfa_cee.c492
-rw-r--r--drivers/scsi/bfa/bfa_core.c402
-rw-r--r--drivers/scsi/bfa/bfa_csdebug.c58
-rw-r--r--drivers/scsi/bfa/bfa_fcpim.c175
-rw-r--r--drivers/scsi/bfa/bfa_fcpim_priv.h188
-rw-r--r--drivers/scsi/bfa/bfa_fcport.c1668
-rw-r--r--drivers/scsi/bfa/bfa_fcs.c182
-rw-r--r--drivers/scsi/bfa/bfa_fcs_lport.c939
-rw-r--r--drivers/scsi/bfa/bfa_fcs_port.c68
-rw-r--r--drivers/scsi/bfa/bfa_fcs_uf.c105
-rw-r--r--drivers/scsi/bfa/bfa_fcxp.c782
-rw-r--r--drivers/scsi/bfa/bfa_fcxp_priv.h138
-rw-r--r--drivers/scsi/bfa/bfa_fwimg_priv.h31
-rw-r--r--drivers/scsi/bfa/bfa_hw_cb.c142
-rw-r--r--drivers/scsi/bfa/bfa_hw_ct.c162
-rw-r--r--drivers/scsi/bfa/bfa_intr.c218
-rw-r--r--drivers/scsi/bfa/bfa_intr_priv.h117
-rw-r--r--drivers/scsi/bfa/bfa_ioc.c2382
-rw-r--r--drivers/scsi/bfa/bfa_ioc.h259
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.c872
-rw-r--r--drivers/scsi/bfa/bfa_iocfc.h168
-rw-r--r--drivers/scsi/bfa/bfa_iocfc_q.c44
-rw-r--r--drivers/scsi/bfa/bfa_ioim.c1311
-rw-r--r--drivers/scsi/bfa/bfa_itnim.c1088
-rw-r--r--drivers/scsi/bfa/bfa_log.c346
-rw-r--r--drivers/scsi/bfa/bfa_log_module.c451
-rw-r--r--drivers/scsi/bfa/bfa_lps.c782
-rw-r--r--drivers/scsi/bfa/bfa_lps_priv.h38
-rw-r--r--drivers/scsi/bfa/bfa_module.c90
-rw-r--r--drivers/scsi/bfa/bfa_modules_priv.h43
-rw-r--r--drivers/scsi/bfa/bfa_os_inc.h222
-rw-r--r--drivers/scsi/bfa/bfa_port.c460
-rw-r--r--drivers/scsi/bfa/bfa_port_priv.h90
-rw-r--r--drivers/scsi/bfa/bfa_priv.h113
-rw-r--r--drivers/scsi/bfa/bfa_rport.c911
-rw-r--r--drivers/scsi/bfa/bfa_rport_priv.h45
-rw-r--r--drivers/scsi/bfa/bfa_sgpg.c231
-rw-r--r--drivers/scsi/bfa/bfa_sgpg_priv.h79
-rw-r--r--drivers/scsi/bfa/bfa_sm.c38
-rw-r--r--drivers/scsi/bfa/bfa_timer.c90
-rw-r--r--drivers/scsi/bfa/bfa_trcmod_priv.h66
-rw-r--r--drivers/scsi/bfa/bfa_tskim.c690
-rw-r--r--drivers/scsi/bfa/bfa_uf.c345
-rw-r--r--drivers/scsi/bfa/bfa_uf_priv.h47
-rw-r--r--drivers/scsi/bfa/bfad.c1182
-rw-r--r--drivers/scsi/bfa/bfad_attr.c649
-rw-r--r--drivers/scsi/bfa/bfad_attr.h65
-rw-r--r--drivers/scsi/bfa/bfad_drv.h295
-rw-r--r--drivers/scsi/bfa/bfad_fwimg.c95
-rw-r--r--drivers/scsi/bfa/bfad_im.c1230
-rw-r--r--drivers/scsi/bfa/bfad_im.h150
-rw-r--r--drivers/scsi/bfa/bfad_im_compat.h46
-rw-r--r--drivers/scsi/bfa/bfad_intr.c213
-rw-r--r--drivers/scsi/bfa/bfad_ipfc.h42
-rw-r--r--drivers/scsi/bfa/bfad_os.c50
-rw-r--r--drivers/scsi/bfa/bfad_tm.h59
-rw-r--r--drivers/scsi/bfa/bfad_trcmod.h52
-rw-r--r--drivers/scsi/bfa/fab.c62
-rw-r--r--drivers/scsi/bfa/fabric.c1278
-rw-r--r--drivers/scsi/bfa/fcbuild.c1449
-rw-r--r--drivers/scsi/bfa/fcbuild.h273
-rw-r--r--drivers/scsi/bfa/fcpim.c843
-rw-r--r--drivers/scsi/bfa/fcptm.c68
-rw-r--r--drivers/scsi/bfa/fcs.h30
-rw-r--r--drivers/scsi/bfa/fcs_auth.h37
-rw-r--r--drivers/scsi/bfa/fcs_fabric.h61
-rw-r--r--drivers/scsi/bfa/fcs_fcpim.h44
-rw-r--r--drivers/scsi/bfa/fcs_fcptm.h45
-rw-r--r--drivers/scsi/bfa/fcs_fcxp.h29
-rw-r--r--drivers/scsi/bfa/fcs_lport.h117
-rw-r--r--drivers/scsi/bfa/fcs_ms.h35
-rw-r--r--drivers/scsi/bfa/fcs_port.h32
-rw-r--r--drivers/scsi/bfa/fcs_rport.h61
-rw-r--r--drivers/scsi/bfa/fcs_trcmod.h56
-rw-r--r--drivers/scsi/bfa/fcs_uf.h32
-rw-r--r--drivers/scsi/bfa/fcs_vport.h39
-rw-r--r--drivers/scsi/bfa/fdmi.c1223
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen.h92
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_adapter.h31
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_audit.h31
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_ethport.h35
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_ioc.h37
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_itnim.h33
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_lport.h51
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_port.h57
-rw-r--r--drivers/scsi/bfa/include/aen/bfa_aen_rport.h37
-rw-r--r--drivers/scsi/bfa/include/bfa.h177
-rw-r--r--drivers/scsi/bfa/include/bfa_fcpim.h159
-rw-r--r--drivers/scsi/bfa/include/bfa_fcptm.h47
-rw-r--r--drivers/scsi/bfa/include/bfa_svc.h324
-rw-r--r--drivers/scsi/bfa/include/bfa_timer.h53
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi.h174
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_boot.h34
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_cbreg.h305
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_cee.h119
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_ctreg.h611
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_fabric.h92
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_fcpim.h301
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_fcxp.h71
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_ioc.h202
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_iocfc.h177
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_lport.h89
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_lps.h96
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_port.h115
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_pport.h184
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_rport.h104
-rw-r--r--drivers/scsi/bfa/include/bfi/bfi_uf.h52
-rw-r--r--drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h36
-rw-r--r--drivers/scsi/bfa/include/cna/cee/bfa_cee.h77
-rw-r--r--drivers/scsi/bfa/include/cna/port/bfa_port.h69
-rw-r--r--drivers/scsi/bfa/include/cna/pstats/ethport_defs.h36
-rw-r--r--drivers/scsi/bfa/include/cna/pstats/phyport_defs.h218
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_checksum.h60
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_debug.h44
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_log.h184
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_perf.h34
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_plog.h162
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_q.h81
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_sm.h69
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_trc.h176
-rw-r--r--drivers/scsi/bfa/include/cs/bfa_wc.h68
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_adapter.h82
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_aen.h73
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_audit.h38
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_auth.h112
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_boot.h71
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_cee.h159
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_driver.h40
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_ethport.h98
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h45
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_im_common.h32
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_im_team.h72
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_ioc.h152
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h310
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h70
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_itnim.h126
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_led.h35
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_lport.h68
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_mfg.h58
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pci.h41
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pm.h33
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pom.h56
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_port.h245
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_pport.h383
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_qos.h99
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_rport.h199
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_status.h255
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_tin.h118
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h43
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_types.h30
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_version.h22
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_vf.h74
-rw-r--r--drivers/scsi/bfa/include/defs/bfa_defs_vport.h91
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb.h33
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h76
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_port.h113
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h80
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h47
-rw-r--r--drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h47
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs.h73
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h82
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h112
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h131
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h63
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h227
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h104
-rw-r--r--drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h63
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_fcs.h28
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_hal.h30
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_linux.h44
-rw-r--r--drivers/scsi/bfa/include/log/bfa_log_wdrv.h36
-rw-r--r--drivers/scsi/bfa/include/protocol/ct.h492
-rw-r--r--drivers/scsi/bfa/include/protocol/fc.h1105
-rw-r--r--drivers/scsi/bfa/include/protocol/fc_sp.h224
-rw-r--r--drivers/scsi/bfa/include/protocol/fcp.h186
-rw-r--r--drivers/scsi/bfa/include/protocol/fdmi.h163
-rw-r--r--drivers/scsi/bfa/include/protocol/pcifw.h75
-rw-r--r--drivers/scsi/bfa/include/protocol/scsi.h1648
-rw-r--r--drivers/scsi/bfa/include/protocol/types.h42
-rw-r--r--drivers/scsi/bfa/loop.c213
-rw-r--r--drivers/scsi/bfa/lport_api.c290
-rw-r--r--drivers/scsi/bfa/lport_priv.h82
-rw-r--r--drivers/scsi/bfa/ms.c759
-rw-r--r--drivers/scsi/bfa/n2n.c105
-rw-r--r--drivers/scsi/bfa/ns.c1242
-rw-r--r--drivers/scsi/bfa/plog.c184
-rw-r--r--drivers/scsi/bfa/rport.c2618
-rw-r--r--drivers/scsi/bfa/rport_api.c180
-rw-r--r--drivers/scsi/bfa/rport_ftrs.c373
-rw-r--r--drivers/scsi/bfa/scn.c482
-rw-r--r--drivers/scsi/bfa/vfapi.c292
-rw-r--r--drivers/scsi/bfa/vport.c891
-rw-r--r--drivers/scsi/bnx2i/bnx2i.h2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_hwi.c2
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c2
-rw-r--r--drivers/scsi/cxgb3i/cxgb3i_iscsi.c2
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c2
-rw-r--r--drivers/scsi/hptiop.c37
-rw-r--r--drivers/scsi/hptiop.h3
-rw-r--r--drivers/scsi/iscsi_tcp.c2
-rw-r--r--drivers/scsi/libiscsi.c6
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c15
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c738
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h149
-rw-r--r--drivers/scsi/mpt2sas/Kconfig2
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h104
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h472
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_history.txt334
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_init.h18
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h81
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_raid.h14
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h148
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c598
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h137
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_config.c22
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c258
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.h6
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_debug.h2
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c1277
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c112
-rw-r--r--drivers/scsi/mvsas/mv_defs.h4
-rw-r--r--drivers/scsi/mvsas/mv_init.c4
-rw-r--r--drivers/scsi/pmcraid.c58
-rw-r--r--drivers/scsi/qla2xxx/qla_mid.c6
-rw-r--r--drivers/scsi/scsi.c11
-rw-r--r--drivers/scsi/scsi_debug.c139
-rw-r--r--drivers/scsi/scsi_error.c3
-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.c72
-rw-r--r--drivers/scsi/sd.c140
-rw-r--r--drivers/scsi/sd.h9
-rw-r--r--drivers/scsi/sd_dif.c65
-rw-r--r--drivers/scsi/sg.c10
-rw-r--r--drivers/scsi/sr.c22
-rw-r--r--drivers/scsi/st.c3
-rw-r--r--drivers/scsi/stex.c282
-rw-r--r--drivers/serial/serial_core.c7
-rw-r--r--drivers/serial/serial_cs.c12
-rw-r--r--drivers/sh/maple/maple.c4
-rw-r--r--drivers/spi/amba-pl022.c2
-rw-r--r--drivers/spi/au1550_spi.c6
-rw-r--r--drivers/ssb/driver_pcicore.c4
-rw-r--r--drivers/staging/Kconfig4
-rw-r--r--drivers/staging/Makefile2
-rw-r--r--drivers/staging/agnx/Kconfig5
-rw-r--r--drivers/staging/agnx/Makefile8
-rw-r--r--drivers/staging/agnx/TODO22
-rw-r--r--drivers/staging/agnx/agnx.h156
-rw-r--r--drivers/staging/agnx/debug.h416
-rw-r--r--drivers/staging/agnx/pci.c635
-rw-r--r--drivers/staging/agnx/phy.c960
-rw-r--r--drivers/staging/agnx/phy.h409
-rw-r--r--drivers/staging/agnx/rf.c893
-rw-r--r--drivers/staging/agnx/sta.c218
-rw-r--r--drivers/staging/agnx/sta.h222
-rw-r--r--drivers/staging/agnx/table.c168
-rw-r--r--drivers/staging/agnx/table.h10
-rw-r--r--drivers/staging/agnx/xmit.c836
-rw-r--r--drivers/staging/agnx/xmit.h250
-rw-r--r--drivers/staging/b3dfg/b3dfg.c1
-rw-r--r--drivers/staging/comedi/Kconfig2
-rw-r--r--drivers/staging/comedi/comedi_fops.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidio.c8
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.c18
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c1
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c12
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c1
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c1
-rw-r--r--drivers/staging/comedi/drivers/ni_pcimio.c22
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c2
-rw-r--r--drivers/staging/comedi/drivers/s526.c109
-rw-r--r--drivers/staging/comedi/drivers/serial2002.c1
-rw-r--r--drivers/staging/cowloop/Kconfig16
-rw-r--r--drivers/staging/cowloop/Makefile1
-rw-r--r--drivers/staging/cowloop/TODO11
-rw-r--r--drivers/staging/cowloop/cowloop.c2842
-rw-r--r--drivers/staging/cowloop/cowloop.h66
-rw-r--r--drivers/staging/et131x/et1310_address_map.h2
-rw-r--r--drivers/staging/et131x/et1310_rx.c20
-rw-r--r--drivers/staging/hv/osd.c1
-rw-r--r--drivers/staging/iio/Kconfig1
-rw-r--r--drivers/staging/iio/industrialio-core.c2
-rw-r--r--drivers/staging/p9auth/p9auth.c14
-rw-r--r--drivers/staging/panel/panel.c2
-rw-r--r--drivers/staging/poch/poch.c1
-rw-r--r--drivers/staging/rt2860/common/cmm_data_2860.c2
-rw-r--r--drivers/staging/rt2860/common/cmm_info.c1
-rw-r--r--drivers/staging/rt2860/rt_linux.c1
-rw-r--r--drivers/staging/rt3090/common/cmm_info.c1
-rw-r--r--drivers/staging/rt3090/rt_linux.c1
-rw-r--r--drivers/staging/rtl8187se/Kconfig3
-rw-r--r--drivers/staging/rtl8192e/Kconfig3
-rw-r--r--drivers/staging/rtl8192e/r8192E_core.c1
-rw-r--r--drivers/staging/sep/sep_driver.c1
-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/vme/bridges/vme_ca91cx42.c1
-rw-r--r--drivers/staging/vme/bridges/vme_tsi148.c1
-rw-r--r--drivers/staging/vt6655/Kconfig4
-rw-r--r--drivers/staging/vt6656/Kconfig4
-rw-r--r--drivers/staging/winbond/wbusb.c44
-rw-r--r--drivers/uio/uio.c1
-rw-r--r--drivers/usb/class/usbtmc.c2
-rw-r--r--drivers/usb/gadget/ether.c9
-rw-r--r--drivers/usb/gadget/imx_udc.c8
-rw-r--r--drivers/usb/gadget/r8a66597-udc.h105
-rw-r--r--drivers/usb/host/ehci-sched.c13
-rw-r--r--drivers/usb/host/isp1362-hcd.c18
-rw-r--r--drivers/usb/host/isp1362.h12
-rw-r--r--drivers/usb/host/pci-quirks.c2
-rw-r--r--drivers/usb/host/whci/asl.c23
-rw-r--r--drivers/usb/host/whci/pzl.c24
-rw-r--r--drivers/usb/host/xhci-hcd.c29
-rw-r--r--drivers/usb/misc/usblcd.c3
-rw-r--r--drivers/usb/musb/Kconfig4
-rw-r--r--drivers/usb/musb/blackfin.c1
-rw-r--r--drivers/usb/musb/musb_core.h7
-rw-r--r--drivers/usb/musb/musb_regs.h9
-rw-r--r--drivers/usb/serial/aircable.c10
-rw-r--r--drivers/usb/serial/cp210x.c1
-rw-r--r--drivers/usb/serial/cypress_m8.c12
-rw-r--r--drivers/usb/serial/digi_acceleport.c8
-rw-r--r--drivers/usb/serial/empeg.c2
-rw-r--r--drivers/usb/serial/ftdi_sio.c422
-rw-r--r--drivers/usb/serial/garmin_gps.c12
-rw-r--r--drivers/usb/serial/generic.c2
-rw-r--r--drivers/usb/serial/ipaq.c9
-rw-r--r--drivers/usb/serial/keyspan_pda.c2
-rw-r--r--drivers/usb/serial/kl5kusb105.c2
-rw-r--r--drivers/usb/serial/mct_u232.c14
-rw-r--r--drivers/usb/serial/opticon.c13
-rw-r--r--drivers/usb/serial/option.c8
-rw-r--r--drivers/usb/serial/oti6858.c6
-rw-r--r--drivers/usb/serial/pl2303.c8
-rw-r--r--drivers/usb/serial/sierra.c2
-rw-r--r--drivers/usb/serial/symbolserial.c22
-rw-r--r--drivers/usb/serial/usb-serial.c10
-rw-r--r--drivers/usb/serial/visor.c28
-rw-r--r--drivers/usb/serial/whiteheat.c10
-rw-r--r--drivers/usb/storage/transport.c46
-rw-r--r--drivers/usb/storage/unusual_devs.h7
-rw-r--r--drivers/usb/wusbcore/security.c41
-rw-r--r--drivers/uwb/whc-rc.c1
-rw-r--r--drivers/video/backlight/adp5520_bl.c123
-rw-r--r--drivers/video/backlight/lcd.c2
-rw-r--r--drivers/video/da8xx-fb.c1
-rw-r--r--drivers/video/msm/mddi.c2
-rw-r--r--drivers/video/omap/blizzard.c10
-rw-r--r--drivers/video/omap/omapfb_main.c22
-rw-r--r--drivers/virtio/virtio_balloon.c3
-rw-r--r--drivers/watchdog/riowd.c2
-rw-r--r--firmware/Makefile9
-rw-r--r--firmware/WHENCE9
-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--firmware/cis/COMpad2.cis.ihex11
-rw-r--r--firmware/cis/COMpad4.cis.ihex9
-rw-r--r--firmware/cis/DP83903.cis.ihex14
-rw-r--r--firmware/cis/NE2K.cis.ihex8
-rw-r--r--firmware/cis/tamarack.cis.ihex10
-rw-r--r--fs/btrfs/acl.c6
-rw-r--r--fs/btrfs/async-thread.c81
-rw-r--r--fs/btrfs/async-thread.h10
-rw-r--r--fs/btrfs/btrfs_inode.h18
-rw-r--r--fs/btrfs/ctree.h19
-rw-r--r--fs/btrfs/disk-io.c50
-rw-r--r--fs/btrfs/extent-tree.c252
-rw-r--r--fs/btrfs/extent_io.c42
-rw-r--r--fs/btrfs/extent_io.h18
-rw-r--r--fs/btrfs/file.c44
-rw-r--r--fs/btrfs/inode.c144
-rw-r--r--fs/btrfs/ioctl.c7
-rw-r--r--fs/btrfs/ordered-data.c6
-rw-r--r--fs/btrfs/relocation.c4
-rw-r--r--fs/btrfs/super.c9
-rw-r--r--fs/btrfs/transaction.c45
-rw-r--r--fs/btrfs/transaction.h5
-rw-r--r--fs/btrfs/tree-log.c56
-rw-r--r--fs/btrfs/tree-log.h3
-rw-r--r--fs/btrfs/xattr.c2
-rw-r--r--fs/cifs/connect.c3
-rw-r--r--fs/dlm/lowcomms.c36
-rw-r--r--fs/ecryptfs/Kconfig3
-rw-r--r--fs/ecryptfs/main.c7
-rw-r--r--fs/ext3/super.c13
-rw-r--r--fs/file.c1
-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/inode.c2
-rw-r--r--fs/gfs2/log.c2
-rw-r--r--fs/gfs2/lops.c2
-rw-r--r--fs/gfs2/ops_fstype.c140
-rw-r--r--fs/gfs2/quota.c372
-rw-r--r--fs/gfs2/quota.h3
-rw-r--r--fs/gfs2/rgrp.c2
-rw-r--r--fs/gfs2/super.c23
-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/isofs/compress.c533
-rw-r--r--fs/isofs/rock.c3
-rw-r--r--fs/nfs/client.c2
-rw-r--r--fs/nfs/nfs4namespace.c12
-rw-r--r--fs/nfs/nfs4renewd.c6
-rw-r--r--fs/nfs/super.c36
-rw-r--r--fs/nfsd/export.c22
-rw-r--r--fs/nfsd/nfs4state.c3
-rw-r--r--fs/nfsd/nfsproc.c1
-rw-r--r--fs/nfsd/vfs.c62
-rw-r--r--fs/partitions/check.c12
-rw-r--r--fs/proc/kcore.c1
-rw-r--r--fs/proc/page.c5
-rw-r--r--fs/quota/Kconfig2
-rw-r--r--fs/quota/dquot.c93
-rw-r--r--fs/quota/quota.c93
-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/romfs/storage.c4
-rw-r--r--fs/sysfs/dir.c3
-rw-r--r--fs/sysfs/file.c14
-rw-r--r--fs/xattr_acl.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c38
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c9
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c41
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c59
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c36
-rw-r--r--fs/xfs/quota/xfs_qm_syscalls.c1
-rw-r--r--fs/xfs/xfs_dfrag.c8
-rw-r--r--fs/xfs/xfs_dir2_leaf.c4
-rw-r--r--fs/xfs/xfs_inode.c4
-rw-r--r--fs/xfs/xfs_inode.h2
-rw-r--r--fs/xfs/xfs_inode_item.c18
-rw-r--r--fs/xfs/xfs_itable.c21
-rw-r--r--fs/xfs/xfs_vnodeops.c6
-rw-r--r--include/acpi/acpixf.h2
-rw-r--r--include/asm-generic/hardirq.h2
-rw-r--r--include/asm-generic/socket.h1
-rw-r--r--include/drm/drm_crtc_helper.h3
-rw-r--r--include/drm/drm_fb_helper.h7
-rw-r--r--include/drm/drm_pciids.h4
-rw-r--r--include/linux/Kbuild2
-rw-r--r--include/linux/ata.h9
-rw-r--r--include/linux/blkdev.h4
-rw-r--r--include/linux/can/dev.h16
-rw-r--r--include/linux/can/platform/ti_hecc.h40
-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/elf.h1
-rw-r--r--include/linux/ethtool.h36
-rw-r--r--include/linux/firewire.h16
-rw-r--r--include/linux/ftrace.h2
-rw-r--r--include/linux/futex.h4
-rw-r--r--include/linux/genhd.h21
-rw-r--r--include/linux/i2c.h94
-rw-r--r--include/linux/i2c/twl4030.h6
-rw-r--r--include/linux/if_tunnel.h12
-rw-r--r--include/linux/init.h1
-rw-r--r--include/linux/interrupt.h2
-rw-r--r--include/linux/ipv6.h2
-rw-r--r--include/linux/kernel.h6
-rw-r--r--include/linux/kvm_host.h52
-rw-r--r--include/linux/libata.h12
-rw-r--r--include/linux/lru_cache.h294
-rw-r--r--include/linux/mfd/ab4500.h262
-rw-r--r--include/linux/mfd/adp5520.h299
-rw-r--r--include/linux/mfd/tmio.h40
-rw-r--r--include/linux/mfd/wm831x/core.h3
-rw-r--r--include/linux/mfd/wm8350/core.h4
-rw-r--r--include/linux/mfd/wm8350/gpio.h18
-rw-r--r--include/linux/mmc/host.h1
-rw-r--r--include/linux/mmdebug.h2
-rw-r--r--include/linux/mmzone.h2
-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/net.h1
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/linux/nl80211.h2
-rw-r--r--include/linux/notifier.h1
-rw-r--r--include/linux/page-flags.h2
-rw-r--r--include/linux/pci.h3
-rw-r--r--include/linux/pci_ids.h3
-rw-r--r--include/linux/perf_event.h5
-rw-r--r--include/linux/posix_acl.h14
-rw-r--r--include/linux/quota.h11
-rw-r--r--include/linux/rcu_types.h18
-rw-r--r--include/linux/rcupdate.h29
-rw-r--r--include/linux/rcutree.h13
-rw-r--r--include/linux/reiserfs_fs.h71
-rw-r--r--include/linux/reiserfs_fs_sb.h20
-rw-r--r--include/linux/sched.h4
-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/smsc911x.h1
-rw-r--r--include/linux/socket.h31
-rw-r--r--include/linux/ssb/ssb.h20
-rw-r--r--include/linux/syscalls.h4
-rw-r--r--include/linux/udp.h6
-rw-r--r--include/linux/usb/serial.h1
-rw-r--r--include/linux/usb/usbnet.h1
-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/workqueue.h1
-rw-r--r--include/net/bluetooth/bluetooth.h2
-rw-r--r--include/net/cfg80211.h40
-rw-r--r--include/net/compat.h8
-rw-r--r--include/net/gen_stats.h1
-rw-r--r--include/net/inet_hashtables.h4
-rw-r--r--include/net/ip_fib.h25
-rw-r--r--include/net/ipip.h19
-rw-r--r--include/net/iw_handler.h14
-rw-r--r--include/net/mac80211.h2
-rw-r--r--include/net/net_namespace.h2
-rw-r--r--include/net/phonet/phonet.h1
-rw-r--r--include/net/phonet/pn_dev.h6
-rw-r--r--include/net/sock.h16
-rw-r--r--include/net/udp.h13
-rw-r--r--include/net/wext.h49
-rw-r--r--include/scsi/libiscsi.h3
-rw-r--r--include/scsi/scsi.h3
-rw-r--r--include/scsi/scsi_cmnd.h4
-rw-r--r--include/scsi/scsi_host.h15
-rw-r--r--include/sound/Kbuild1
-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.h1
-rw-r--r--include/sound/sscape_ioctl.h21
-rw-r--r--include/sound/tpa6130a2-plat.h (renamed from drivers/net/wireless/wl12xx/wl1251_netlink.h)18
-rw-r--r--include/trace/events/gfs2.h (renamed from fs/gfs2/trace_gfs2.h)7
-rw-r--r--init/Kconfig25
-rw-r--r--init/Makefile6
-rw-r--r--init/main.c1
-rw-r--r--init/version.c4
-rw-r--r--kernel/bounds.c2
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c10
-rw-r--r--kernel/futex.c3
-rw-r--r--kernel/hrtimer.c2
-rw-r--r--kernel/irq/handle.c1
-rw-r--r--kernel/kexec.c2
-rw-r--r--kernel/kgdb.c31
-rw-r--r--kernel/lockdep.c20
-rw-r--r--kernel/mutex-debug.c1
-rw-r--r--kernel/panic.c3
-rw-r--r--kernel/perf_event.c282
-rw-r--r--kernel/rcupdate.c140
-rw-r--r--kernel/rcutorture.c4
-rw-r--r--kernel/rcutree.c330
-rw-r--r--kernel/rcutree.h86
-rw-r--r--kernel/rcutree_plugin.h103
-rw-r--r--kernel/rcutree_trace.c4
-rw-r--r--kernel/sched.c33
-rw-r--r--kernel/softlockup.c16
-rw-r--r--kernel/sys_ni.c2
-rw-r--r--kernel/time/tick-sched.c9
-rw-r--r--kernel/time/timekeeping.c1
-rw-r--r--kernel/trace/ftrace.c27
-rw-r--r--kernel/trace/kmemtrace.c2
-rw-r--r--kernel/trace/trace.c4
-rw-r--r--kernel/trace/trace_branch.c8
-rw-r--r--kernel/trace/trace_event_profile.c15
-rw-r--r--kernel/trace/trace_events_filter.c3
-rw-r--r--kernel/trace/trace_hw_branches.c8
-rw-r--r--kernel/trace/trace_output.c18
-rw-r--r--kernel/trace/trace_syscalls.c4
-rw-r--r--kernel/workqueue.c18
-rw-r--r--lib/Kconfig3
-rw-r--r--lib/Kconfig.debug27
-rw-r--r--lib/Makefile2
-rw-r--r--lib/debugobjects.c1
-rw-r--r--lib/fault-inject.c1
-rw-r--r--lib/lru_cache.c560
-rw-r--r--mm/Kconfig4
-rw-r--r--mm/Makefile1
-rw-r--r--mm/backing-dev.c2
-rw-r--r--mm/kmemleak.c5
-rw-r--r--mm/ksm.c10
-rw-r--r--mm/page-writeback.c3
-rw-r--r--mm/percpu.c5
-rw-r--r--mm/slqb.c3791
-rw-r--r--mm/slub.c18
-rw-r--r--mm/vmalloc.c50
-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/sock.c2
-rw-r--r--net/bluetooth/cmtp/sock.c2
-rw-r--r--net/bluetooth/hci_sock.c2
-rw-r--r--net/bluetooth/hidp/sock.c2
-rw-r--r--net/bluetooth/l2cap.c2
-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/dev.c21
-rw-r--r--net/core/ethtool.c81
-rw-r--r--net/core/gen_stats.c8
-rw-r--r--net/core/net-sysfs.c50
-rw-r--r--net/core/pktgen.c15
-rw-r--r--net/core/sock.c32
-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/ipv6.c12
-rw-r--r--net/dccp/probe.c16
-rw-r--r--net/dccp/proto.c13
-rw-r--r--net/decnet/af_decnet.c2
-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/af_inet.c2
-rw-r--r--net/ipv4/cipso_ipv4.c2
-rw-r--r--net/ipv4/devinet.c16
-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.c1
-rw-r--r--net/ipv4/inet_diag.c2
-rw-r--r--net/ipv4/inet_hashtables.c2
-rw-r--r--net/ipv4/inet_timewait_sock.c2
-rw-r--r--net/ipv4/ip_gre.c5
-rw-r--r--net/ipv4/ipip.c5
-rw-r--r--net/ipv4/ipmr.c12
-rw-r--r--net/ipv4/raw.c3
-rw-r--r--net/ipv4/syncookies.c3
-rw-r--r--net/ipv4/tcp.c11
-rw-r--r--net/ipv4/tcp_ipv4.c6
-rw-r--r--net/ipv4/tcp_minisocks.c1
-rw-r--r--net/ipv4/udp.c185
-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.c3
-rw-r--r--net/ipv6/datagram.c25
-rw-r--r--net/ipv6/inet6_connection_sock.c1
-rw-r--r--net/ipv6/inet6_hashtables.c2
-rw-r--r--net/ipv6/ipv6_sockglue.c1
-rw-r--r--net/ipv6/ndisc.c1
-rw-r--r--net/ipv6/raw.c5
-rw-r--r--net/ipv6/route.c3
-rw-r--r--net/ipv6/sit.c134
-rw-r--r--net/ipv6/syncookies.c1
-rw-r--r--net/ipv6/tcp_ipv6.c16
-rw-r--r--net/ipv6/udp.c20
-rw-r--r--net/ipx/af_ipx.c2
-rw-r--r--net/irda/af_irda.c2
-rw-r--r--net/irda/ircomm/ircomm_tty_attach.c1
-rw-r--r--net/irda/irlan/irlan_common.c1
-rw-r--r--net/irda/irlan/irlan_eth.c1
-rw-r--r--net/irda/irnet/irnet_irda.c1
-rw-r--r--net/irda/irnet/irnet_ppp.c1
-rw-r--r--net/iucv/af_iucv.c2
-rw-r--r--net/key/af_key.c4
-rw-r--r--net/llc/af_llc.c2
-rw-r--r--net/mac80211/ibss.c4
-rw-r--r--net/mac80211/iface.c14
-rw-r--r--net/mac80211/mlme.c24
-rw-r--r--net/mac80211/rc80211_pid_debugfs.c1
-rw-r--r--net/mac80211/rx.c12
-rw-r--r--net/mac80211/scan.c10
-rw-r--r--net/mac80211/sta_info.c2
-rw-r--r--net/mac80211/tx.c3
-rw-r--r--net/mac80211/util.c4
-rw-r--r--net/netfilter/nf_conntrack_core.c1
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/netrom/af_netrom.c2
-rw-r--r--net/packet/af_packet.c12
-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/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.c3
-rw-r--r--net/sched/act_pedit.c2
-rw-r--r--net/sched/cls_api.c2
-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/socket.c2
-rw-r--r--net/socket.c247
-rw-r--r--net/sunrpc/svcauth_unix.c3
-rw-r--r--net/sunrpc/xprtrdma/svc_rdma_transport.c1
-rw-r--r--net/unix/af_unix.c2
-rw-r--r--net/wireless/Kconfig50
-rw-r--r--net/wireless/Makefile10
-rw-r--r--net/wireless/core.c25
-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.c47
-rw-r--r--net/wireless/nl80211.c9
-rw-r--r--net/wireless/scan.c6
-rw-r--r--net/wireless/sme.c12
-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--scripts/.gitignore1
-rw-r--r--scripts/Kbuild.include2
-rw-r--r--scripts/Makefile.lib2
-rw-r--r--scripts/basic/fixdep.c10
-rw-r--r--scripts/binoffset.c163
-rwxr-xr-xscripts/checkkconfigsymbols.sh4
-rwxr-xr-xscripts/extract-ikconfig127
-rw-r--r--scripts/headers_install.pl2
-rw-r--r--scripts/kconfig/confdata.c2
-rwxr-xr-xscripts/mkcompile_h14
-rw-r--r--scripts/package/Makefile11
-rwxr-xr-xscripts/package/mkspec2
-rw-r--r--security/keys/keyctl.c2
-rw-r--r--sound/arm/aaci.c1
-rw-r--r--sound/core/isadma.c10
-rw-r--r--sound/drivers/opl3/opl3_midi.c28
-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/au1550_ac97.c16
-rw-r--r--sound/pci/Kconfig1
-rw-r--r--sound/pci/bt87x.c2
-rw-r--r--sound/pci/hda/hda_intel.c16
-rw-r--r--sound/pci/hda/patch_nvhdmi.c31
-rw-r--r--sound/pci/hda/patch_realtek.c230
-rw-r--r--sound/pci/hda/patch_sigmatel.c29
-rw-r--r--sound/pci/hda/patch_via.c3501
-rw-r--r--sound/pci/ice1712/Makefile2
-rw-r--r--sound/pci/ice1712/amp.c8
-rw-r--r--sound/pci/ice1712/ice1712.c14
-rw-r--r--sound/pci/ice1712/ice1712.h14
-rw-r--r--sound/pci/ice1712/ice1724.c111
-rw-r--r--sound/pci/ice1712/juli.c24
-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/pci/via82xx.c27
-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/Kconfig12
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/ak4671.c825
-rw-r--r--sound/soc/codecs/ak4671.h156
-rw-r--r--sound/soc/codecs/tpa6130a2.c463
-rw-r--r--sound/soc/codecs/tpa6130a2.h62
-rw-r--r--sound/soc/codecs/wm8350.c6
-rw-r--r--sound/soc/codecs/wm8400.c3
-rw-r--r--sound/soc/codecs/wm8510.c4
-rw-r--r--sound/soc/codecs/wm8580.c4
-rw-r--r--sound/soc/codecs/wm8711.c659
-rw-r--r--sound/soc/codecs/wm8711.h42
-rw-r--r--sound/soc/codecs/wm8753.c4
-rw-r--r--sound/soc/codecs/wm8900.c4
-rw-r--r--sound/soc/codecs/wm8940.c6
-rw-r--r--sound/soc/codecs/wm8960.c4
-rw-r--r--sound/soc/codecs/wm8974.c27
-rw-r--r--sound/soc/codecs/wm8990.c4
-rw-r--r--sound/soc/codecs/wm8993.c38
-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/imx/mxc-ssi.c8
-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.c8
-rw-r--r--sound/soc/s3c24xx/s3c-i2s-v2.c30
-rw-r--r--sound/soc/s3c24xx/s3c64xx-i2s.c19
-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.c62
-rw-r--r--sound/soc/soc-dapm.c140
-rw-r--r--sound/usb/usx2y/us122l.c75
-rw-r--r--tools/perf/Documentation/perf-timechart.txt3
-rw-r--r--tools/perf/Makefile23
-rw-r--r--tools/perf/builtin-record.c6
-rw-r--r--tools/perf/builtin-sched.c4
-rw-r--r--tools/perf/builtin-stat.c8
-rw-r--r--tools/perf/builtin-timechart.c10
-rw-r--r--tools/perf/builtin-top.c1
-rw-r--r--tools/perf/builtin-trace.c6
-rw-r--r--tools/perf/design.txt3
-rw-r--r--tools/perf/util/parse-events.c5
-rw-r--r--tools/perf/util/svghelper.c14
-rw-r--r--tools/perf/util/symbol.c3
-rw-r--r--tools/perf/util/trace-event-parse.c17
-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.c908
2440 files changed, 192974 insertions, 69876 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-class-usb_host b/Documentation/ABI/testing/sysfs-class-uwb_rc-wusbhc
index 46b66ad1f1b4..4e8106f7cfd9 100644
--- a/Documentation/ABI/testing/sysfs-class-usb_host
+++ b/Documentation/ABI/testing/sysfs-class-uwb_rc-wusbhc
@@ -1,4 +1,4 @@
-What: /sys/class/usb_host/usb_hostN/wusb_chid
+What: /sys/class/uwb_rc/uwbN/wusbhc/wusb_chid
Date: July 2008
KernelVersion: 2.6.27
Contact: David Vrabel <david.vrabel@csr.com>
@@ -9,7 +9,7 @@ Description:
Set an all zero CHID to stop the host controller.
-What: /sys/class/usb_host/usb_hostN/wusb_trust_timeout
+What: /sys/class/uwb_rc/uwbN/wusbhc/wusb_trust_timeout
Date: July 2008
KernelVersion: 2.6.27
Contact: David Vrabel <david.vrabel@csr.com>
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/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/cgroups/cgroups.txt b/Documentation/cgroups/cgroups.txt
index 455d4e6d346d..0b33bfe7dde9 100644
--- a/Documentation/cgroups/cgroups.txt
+++ b/Documentation/cgroups/cgroups.txt
@@ -227,7 +227,14 @@ as the path relative to the root of the cgroup file system.
Each cgroup is represented by a directory in the cgroup file system
containing the following files describing that cgroup:
- - tasks: list of tasks (by pid) attached to that cgroup
+ - tasks: list of tasks (by pid) attached to that cgroup. This list
+ is not guaranteed to be sorted. Writing a thread id into this file
+ moves the thread into this cgroup.
+ - cgroup.procs: list of tgids in the cgroup. This list is not
+ guaranteed to be sorted or free of duplicate tgids, and userspace
+ should sort/uniquify the list if this property is required.
+ Writing a tgid into this file moves all threads with that tgid into
+ this cgroup.
- notify_on_release flag: run the release agent on exit?
- release_agent: the path to use for release notifications (this file
exists in the top cgroup only)
@@ -374,7 +381,7 @@ Now you want to do something with this cgroup.
In this directory you can find several files:
# ls
-notify_on_release tasks
+cgroup.procs notify_on_release tasks
(plus whatever files added by the attached subsystems)
Now attach your shell to this cgroup:
diff --git a/Documentation/debugging-via-ohci1394.txt b/Documentation/debugging-via-ohci1394.txt
index 59a91e5c6909..611f5a5499b1 100644
--- a/Documentation/debugging-via-ohci1394.txt
+++ b/Documentation/debugging-via-ohci1394.txt
@@ -64,14 +64,14 @@ be used to view the printk buffer of a remote machine, even with live update.
Bernhard Kaindl enhanced firescope to support accessing 64-bit machines
from 32-bit firescope and vice versa:
-- ftp://ftp.suse.de/private/bk/firewire/tools/firescope-0.2.2.tar.bz2
+- http://halobates.de/firewire/firescope-0.2.2.tar.bz2
and he implemented fast system dump (alpha version - read README.txt):
-- ftp://ftp.suse.de/private/bk/firewire/tools/firedump-0.1.tar.bz2
+- http://halobates.de/firewire/firedump-0.1.tar.bz2
There is also a gdb proxy for firewire which allows to use gdb to access
data which can be referenced from symbols found by gdb in vmlinux:
-- ftp://ftp.suse.de/private/bk/firewire/tools/fireproxy-0.33.tar.bz2
+- http://halobates.de/firewire/fireproxy-0.33.tar.bz2
The latest version of this gdb proxy (fireproxy-0.34) can communicate (not
yet stable) with kgdb over an memory-based communication module (kgdbom).
@@ -178,7 +178,7 @@ Step-by-step instructions for using firescope with early OHCI initialization:
Notes
-----
-Documentation and specifications: ftp://ftp.suse.de/private/bk/firewire/docs
+Documentation and specifications: http://halobates.de/firewire/
FireWire is a trademark of Apple Inc. - for more information please refer to:
http://en.wikipedia.org/wiki/FireWire
diff --git a/Documentation/dontdiff b/Documentation/dontdiff
index e1efc400bed6..bc01a5a9d663 100644
--- a/Documentation/dontdiff
+++ b/Documentation/dontdiff
@@ -68,7 +68,6 @@ autoconf.h*
bbootsect
bin2c
binkernel.spec
-binoffset
bootsect
bounds.h
bsetup
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 89a47b5aff07..6bf9a7643612 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -404,15 +404,6 @@ 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.
@@ -451,3 +442,33 @@ Why: OSS sound_core grabs all legacy minors (0-255) of SOUND_MAJOR
will also allow making ALSA OSS emulation independent of
sound_core. The dependency will be broken then too.
Who: Tejun Heo <tj@kernel.org>
+
+----------------------------
+
+What: Support for VMware's guest paravirtuliazation technique [VMI] will be
+ dropped.
+When: 2.6.37 or earlier.
+Why: With the recent innovations in CPU hardware acceleration technologies
+ from Intel and AMD, VMware ran a few experiments to compare these
+ techniques to guest paravirtualization technique on VMware's platform.
+ These hardware assisted virtualization techniques have outperformed the
+ performance benefits provided by VMI in most of the workloads. VMware
+ expects that these hardware features will be ubiquitous in a couple of
+ years, as a result, VMware has started a phased retirement of this
+ feature from the hypervisor. We will be removing this feature from the
+ Kernel too. Right now we are targeting 2.6.37 but can retire earlier if
+ technical reasons (read opportunity to remove major chunk of pvops)
+ arise.
+
+ Please note that VMI has always been an optimization and non-VMI kernels
+ still work fine on VMware's platform.
+ Latest versions of VMware's product which support VMI are,
+ Workstation 7.0 and VSphere 4.0 on ESX side, future maintainence
+ releases for these products will continue supporting VMI.
+
+ For more details about VMI retirement take a look at this,
+ http://blogs.vmware.com/guestosguide/2009/09/vmi-retirement.html
+
+Who: Alok N Kataria <akataria@vmware.com>
+
+----------------------------
diff --git a/Documentation/filesystems/ext3.txt b/Documentation/filesystems/ext3.txt
index 570f9bd9be2b..05d5cf1d743f 100644
--- a/Documentation/filesystems/ext3.txt
+++ b/Documentation/filesystems/ext3.txt
@@ -123,10 +123,18 @@ resuid=n The user ID which may use the reserved blocks.
sb=n Use alternate superblock at this location.
-quota
-noquota
-grpquota
-usrquota
+quota These options are ignored by the filesystem. They
+noquota are used only by quota tools to recognize volumes
+grpquota where quota should be turned on. See documentation
+usrquota in the quota-tools package for more details
+ (http://sourceforge.net/projects/linuxquota).
+
+jqfmt=<quota type> These options tell filesystem details about quota
+usrjquota=<file> so that quota information can be properly updated
+grpjquota=<file> during journal replay. They replace the above
+ quota options. See documentation in the quota-tools
+ package for more details
+ (http://sourceforge.net/projects/linuxquota).
bh (*) ext3 associates buffer heads to data pages to
nobh (a) cache disk block mapping information
diff --git a/Documentation/filesystems/nfs41-server.txt b/Documentation/filesystems/nfs41-server.txt
index 5920fe26e6ff..1bd0d0c05171 100644
--- a/Documentation/filesystems/nfs41-server.txt
+++ b/Documentation/filesystems/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/flexible-arrays.txt b/Documentation/flexible-arrays.txt
index 84eb26808dee..cb8a3a00cc92 100644
--- a/Documentation/flexible-arrays.txt
+++ b/Documentation/flexible-arrays.txt
@@ -1,5 +1,5 @@
Using flexible arrays in the kernel
-Last updated for 2.6.31
+Last updated for 2.6.32
Jonathan Corbet <corbet@lwn.net>
Large contiguous memory allocations can be unreliable in the Linux kernel.
@@ -40,6 +40,13 @@ argument is passed directly to the internal memory allocation calls. With
the current code, using flags to ask for high memory is likely to lead to
notably unpleasant side effects.
+It is also possible to define flexible arrays at compile time with:
+
+ DEFINE_FLEX_ARRAY(name, element_size, total);
+
+This macro will result in a definition of an array with the given name; the
+element size and total will be checked for validity at compile time.
+
Storing data into a flexible array is accomplished with a call to:
int flex_array_put(struct flex_array *array, unsigned int element_nr,
@@ -76,16 +83,30 @@ particular element has never been allocated.
Note that it is possible to get back a valid pointer for an element which
has never been stored in the array. Memory for array elements is allocated
one page at a time; a single allocation could provide memory for several
-adjacent elements. The flexible array code does not know if a specific
-element has been written; it only knows if the associated memory is
-present. So a flex_array_get() call on an element which was never stored
-in the array has the potential to return a pointer to random data. If the
-caller does not have a separate way to know which elements were actually
-stored, it might be wise, at least, to add GFP_ZERO to the flags argument
-to ensure that all elements are zeroed.
-
-There is no way to remove a single element from the array. It is possible,
-though, to remove all elements with a call to:
+adjacent elements. Flexible array elements are normally initialized to the
+value FLEX_ARRAY_FREE (defined as 0x6c in <linux/poison.h>), so errors
+involving that number probably result from use of unstored array entries.
+Note that, if array elements are allocated with __GFP_ZERO, they will be
+initialized to zero and this poisoning will not happen.
+
+Individual elements in the array can be cleared with:
+
+ int flex_array_clear(struct flex_array *array, unsigned int element_nr);
+
+This function will set the given element to FLEX_ARRAY_FREE and return
+zero. If storage for the indicated element is not allocated for the array,
+flex_array_clear() will return -EINVAL instead. Note that clearing an
+element does not release the storage associated with it; to reduce the
+allocated size of an array, call:
+
+ int flex_array_shrink(struct flex_array *array);
+
+The return value will be the number of pages of memory actually freed.
+This function works by scanning the array for pages containing nothing but
+FLEX_ARRAY_FREE bytes, so (1) it can be expensive, and (2) it will not work
+if the array's pages are allocated with __GFP_ZERO.
+
+It is possible to remove all elements of an array with a call to:
void flex_array_free_parts(struct flex_array *array);
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/infiniband/user_mad.txt b/Documentation/infiniband/user_mad.txt
index 744687dd195b..8a366959f5cc 100644
--- a/Documentation/infiniband/user_mad.txt
+++ b/Documentation/infiniband/user_mad.txt
@@ -128,8 +128,8 @@ Setting IsSM Capability Bit
To create the appropriate character device files automatically with
udev, a rule like
- KERNEL="umad*", NAME="infiniband/%k"
- KERNEL="issm*", NAME="infiniband/%k"
+ KERNEL=="umad*", NAME="infiniband/%k"
+ KERNEL=="issm*", NAME="infiniband/%k"
can be used. This will create device nodes named
diff --git a/Documentation/infiniband/user_verbs.txt b/Documentation/infiniband/user_verbs.txt
index f847501e50b5..afe3f8da9018 100644
--- a/Documentation/infiniband/user_verbs.txt
+++ b/Documentation/infiniband/user_verbs.txt
@@ -58,7 +58,7 @@ Memory pinning
To create the appropriate character device files automatically with
udev, a rule like
- KERNEL="uverbs*", NAME="infiniband/%k"
+ KERNEL=="uverbs*", NAME="infiniband/%k"
can be used. This will create device nodes named
diff --git a/Documentation/isdn/INTERFACE.CAPI b/Documentation/isdn/INTERFACE.CAPI
index 686e107923ec..5fe8de5cc727 100644
--- a/Documentation/isdn/INTERFACE.CAPI
+++ b/Documentation/isdn/INTERFACE.CAPI
@@ -60,10 +60,9 @@ open() operation on regular files or character devices.
After a successful return from register_appl(), CAPI messages from the
application may be passed to the driver for the device via calls to the
-send_message() callback function. The CAPI message to send is stored in the
-data portion of an skb. Conversely, the driver may call Kernel CAPI's
-capi_ctr_handle_message() function to pass a received CAPI message to Kernel
-CAPI for forwarding to an application, specifying its ApplID.
+send_message() callback function. Conversely, the driver may call Kernel
+CAPI's capi_ctr_handle_message() function to pass a received CAPI message to
+Kernel CAPI for forwarding to an application, specifying its ApplID.
Deregistration requests (CAPI operation CAPI_RELEASE) from applications are
forwarded as calls to the release_appl() callback function, passing the same
@@ -142,6 +141,7 @@ u16 (*send_message)(struct capi_ctr *ctrlr, struct sk_buff *skb)
to accepting or queueing the message. Errors occurring during the
actual processing of the message should be signaled with an
appropriate reply message.
+ May be called in process or interrupt context.
Calls to this function are not serialized by Kernel CAPI, ie. it must
be prepared to be re-entered.
@@ -154,7 +154,8 @@ read_proc_t *ctr_read_proc
system entry, /proc/capi/controllers/<n>; will be called with a
pointer to the device's capi_ctr structure as the last (data) argument
-Note: Callback functions are never called in interrupt context.
+Note: Callback functions except send_message() are never called in interrupt
+context.
- to be filled in before calling capi_ctr_ready():
@@ -171,14 +172,40 @@ u8 serial[CAPI_SERIAL_LEN]
value to return for CAPI_GET_SERIAL
-4.3 The _cmsg Structure
+4.3 SKBs
+
+CAPI messages are passed between Kernel CAPI and the driver via send_message()
+and capi_ctr_handle_message(), stored in the data portion of a socket buffer
+(skb). Each skb contains a single CAPI message coded according to the CAPI 2.0
+standard.
+
+For the data transfer messages, DATA_B3_REQ and DATA_B3_IND, the actual
+payload data immediately follows the CAPI message itself within the same skb.
+The Data and Data64 parameters are not used for processing. The Data64
+parameter may be omitted by setting the length field of the CAPI message to 22
+instead of 30.
+
+
+4.4 The _cmsg Structure
(declared in <linux/isdn/capiutil.h>)
The _cmsg structure stores the contents of a CAPI 2.0 message in an easily
-accessible form. It contains members for all possible CAPI 2.0 parameters, of
-which only those appearing in the message type currently being processed are
-actually used. Unused members should be set to zero.
+accessible form. It contains members for all possible CAPI 2.0 parameters,
+including subparameters of the Additional Info and B Protocol structured
+parameters, with the following exceptions:
+
+* second Calling party number (CONNECT_IND)
+
+* Data64 (DATA_B3_REQ and DATA_B3_IND)
+
+* Sending complete (subparameter of Additional Info, CONNECT_REQ and INFO_REQ)
+
+* Global Configuration (subparameter of B Protocol, CONNECT_REQ, CONNECT_RESP
+ and SELECT_B_PROTOCOL_REQ)
+
+Only those parameters appearing in the message type currently being processed
+are actually used. Unused members should be set to zero.
Members are named after the CAPI 2.0 standard names of the parameters they
represent. See <linux/isdn/capiutil.h> for the exact spelling. Member data
@@ -190,18 +217,19 @@ u16 for CAPI parameters of type 'word'
u32 for CAPI parameters of type 'dword'
-_cstruct for CAPI parameters of type 'struct' not containing any
- variably-sized (struct) subparameters (eg. 'Called Party Number')
+_cstruct for CAPI parameters of type 'struct'
The member is a pointer to a buffer containing the parameter in
CAPI encoding (length + content). It may also be NULL, which will
be taken to represent an empty (zero length) parameter.
+ Subparameters are stored in encoded form within the content part.
-_cmstruct for CAPI parameters of type 'struct' containing 'struct'
- subparameters ('Additional Info' and 'B Protocol')
+_cmstruct alternative representation for CAPI parameters of type 'struct'
+ (used only for the 'Additional Info' and 'B Protocol' parameters)
The representation is a single byte containing one of the values:
- CAPI_DEFAULT: the parameter is empty
- CAPI_COMPOSE: the values of the subparameters are stored
- individually in the corresponding _cmsg structure members
+ CAPI_DEFAULT: The parameter is empty/absent.
+ CAPI_COMPOSE: The parameter is present.
+ Subparameter values are stored individually in the corresponding
+ _cmsg structure members.
Functions capi_cmsg2message() and capi_message2cmsg() are provided to convert
messages between their transport encoding described in the CAPI 2.0 standard
@@ -297,3 +325,26 @@ char *capi_cmd2str(u8 Command, u8 Subcommand)
be NULL if the command/subcommand is not one of those defined in the
CAPI 2.0 standard.
+
+7. Debugging
+
+The module kernelcapi has a module parameter showcapimsgs controlling some
+debugging output produced by the module. It can only be set when the module is
+loaded, via a parameter "showcapimsgs=<n>" to the modprobe command, either on
+the command line or in the configuration file.
+
+If the lowest bit of showcapimsgs is set, kernelcapi logs controller and
+application up and down events.
+
+In addition, every registered CAPI controller has an associated traceflag
+parameter controlling how CAPI messages sent from and to tha controller are
+logged. The traceflag parameter is initialized with the value of the
+showcapimsgs parameter when the controller is registered, but can later be
+changed via the MANUFACTURER_REQ command KCAPI_CMD_TRACE.
+
+If the value of traceflag is non-zero, CAPI messages are logged.
+DATA_B3 messages are only logged if the value of traceflag is > 2.
+
+If the lowest bit of traceflag is set, only the command/subcommand and message
+length are logged. Otherwise, kernelcapi logs a readable representation of
+the entire message.
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 6fa7292947e5..52c34b4f567e 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -671,6 +671,7 @@ and is between 256 and 4096 characters. It is defined in the file
earlyprintk= [X86,SH,BLACKFIN]
earlyprintk=vga
earlyprintk=serial[,ttySn[,baudrate]]
+ earlyprintk=ttySn[,baudrate]
earlyprintk=dbgp[debugController#]
Append ",keep" to not disable it when the real console
@@ -2589,6 +2590,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/networking/pktgen.txt b/Documentation/networking/pktgen.txt
index c6cf4a3c16e0..61bb645d50e0 100644
--- a/Documentation/networking/pktgen.txt
+++ b/Documentation/networking/pktgen.txt
@@ -90,6 +90,11 @@ Examples:
pgset "dstmac 00:00:00:00:00:00" sets MAC destination address
pgset "srcmac 00:00:00:00:00:00" sets MAC source address
+ pgset "queue_map_min 0" Sets the min value of tx queue interval
+ pgset "queue_map_max 7" Sets the max value of tx queue interval, for multiqueue devices
+ To select queue 1 of a given device,
+ use queue_map_min=1 and queue_map_max=1
+
pgset "src_mac_count 1" Sets the number of MACs we'll range through.
The 'minimum' MAC is what you set with srcmac.
@@ -101,6 +106,9 @@ Examples:
IPDST_RND, UDPSRC_RND,
UDPDST_RND, MACSRC_RND, MACDST_RND
MPLS_RND, VID_RND, SVID_RND
+ QUEUE_MAP_RND # queue map random
+ QUEUE_MAP_CPU # queue map mirrors smp_processor_id()
+
pgset "udp_src_min 9" set UDP source port min, If < udp_src_max, then
cycle through the port range.
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/scsi/hptiop.txt b/Documentation/scsi/hptiop.txt
index a6eb4add1be6..9605179711f4 100644
--- a/Documentation/scsi/hptiop.txt
+++ b/Documentation/scsi/hptiop.txt
@@ -3,6 +3,25 @@ HIGHPOINT ROCKETRAID 3xxx/4xxx ADAPTER DRIVER (hptiop)
Controller Register Map
-------------------------
+For RR44xx Intel IOP based adapters, the controller IOP is accessed via PCI BAR0 and BAR2:
+
+ BAR0 offset Register
+ 0x11C5C Link Interface IRQ Set
+ 0x11C60 Link Interface IRQ Clear
+
+ BAR2 offset Register
+ 0x10 Inbound Message Register 0
+ 0x14 Inbound Message Register 1
+ 0x18 Outbound Message Register 0
+ 0x1C Outbound Message Register 1
+ 0x20 Inbound Doorbell Register
+ 0x24 Inbound Interrupt Status Register
+ 0x28 Inbound Interrupt Mask Register
+ 0x30 Outbound Interrupt Status Register
+ 0x34 Outbound Interrupt Mask Register
+ 0x40 Inbound Queue Port
+ 0x44 Outbound Queue Port
+
For Intel IOP based adapters, the controller IOP is accessed via PCI BAR0:
BAR0 offset Register
@@ -93,7 +112,7 @@ The driver exposes following sysfs attributes:
-----------------------------------------------------------------------------
-Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
+Copyright (C) 2006-2009 HighPoint Technologies, Inc. All Rights Reserved.
This file is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
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/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index 75fddb40f416..4c7f9aee5c4e 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -359,6 +359,7 @@ STAC9227/9228/9229/927x
5stack-no-fp D965 5stack without front panel
dell-3stack Dell Dimension E520
dell-bios Fixes with Dell BIOS setup
+ volknob Fixes with volume-knob widget 0x24
auto BIOS setup (default)
STAC92HD71B*
diff --git a/Documentation/vm/ksm.txt b/Documentation/vm/ksm.txt
index 72a22f65960e..262d8e6793a3 100644
--- a/Documentation/vm/ksm.txt
+++ b/Documentation/vm/ksm.txt
@@ -52,15 +52,15 @@ The KSM daemon is controlled by sysfs files in /sys/kernel/mm/ksm/,
readable by all but writable only by root:
max_kernel_pages - set to maximum number of kernel pages that KSM may use
- e.g. "echo 2000 > /sys/kernel/mm/ksm/max_kernel_pages"
+ e.g. "echo 100000 > /sys/kernel/mm/ksm/max_kernel_pages"
Value 0 imposes no limit on the kernel pages KSM may use;
but note that any process using MADV_MERGEABLE can cause
KSM to allocate these pages, unswappable until it exits.
- Default: 2000 (chosen for demonstration purposes)
+ Default: quarter of memory (chosen to not pin too much)
pages_to_scan - how many present pages to scan before ksmd goes to sleep
- e.g. "echo 200 > /sys/kernel/mm/ksm/pages_to_scan"
- Default: 200 (chosen for demonstration purposes)
+ e.g. "echo 100 > /sys/kernel/mm/ksm/pages_to_scan"
+ Default: 100 (chosen for demonstration purposes)
sleep_millisecs - how many milliseconds ksmd should sleep before next scan
e.g. "echo 20 > /sys/kernel/mm/ksm/sleep_millisecs"
@@ -70,7 +70,8 @@ run - set 0 to stop ksmd from running but keep merged pages,
set 1 to run ksmd e.g. "echo 1 > /sys/kernel/mm/ksm/run",
set 2 to stop ksmd and unmerge all pages currently merged,
but leave mergeable areas registered for next run
- Default: 1 (for immediate use by apps which register)
+ Default: 0 (must be changed to 1 to activate KSM,
+ except if CONFIG_SYSFS is disabled)
The effectiveness of KSM and MADV_MERGEABLE is shown in /sys/kernel/mm/ksm/:
@@ -86,4 +87,4 @@ pages_volatile embraces several different kinds of activity, but a high
proportion there would also indicate poor use of madvise MADV_MERGEABLE.
Izik Eidus,
-Hugh Dickins, 30 July 2009
+Hugh Dickins, 24 Sept 2009
diff --git a/Documentation/vm/page-types.c b/Documentation/vm/page-types.c
index fa1a30d9e9d5..3ec4f2a22585 100644
--- a/Documentation/vm/page-types.c
+++ b/Documentation/vm/page-types.c
@@ -2,7 +2,10 @@
* page-types: Tool for querying page flags
*
* Copyright (C) 2009 Intel corporation
- * Copyright (C) 2009 Wu Fengguang <fengguang.wu@intel.com>
+ *
+ * Authors: Wu Fengguang <fengguang.wu@intel.com>
+ *
+ * Released under the General Public License (GPL).
*/
#define _LARGEFILE64_SOURCE
@@ -69,7 +72,9 @@
#define KPF_COMPOUND_TAIL 16
#define KPF_HUGE 17
#define KPF_UNEVICTABLE 18
+#define KPF_HWPOISON 19
#define KPF_NOPAGE 20
+#define KPF_KSM 21
/* [32-] kernel hacking assistances */
#define KPF_RESERVED 32
@@ -116,7 +121,9 @@ static char *page_flag_names[] = {
[KPF_COMPOUND_TAIL] = "T:compound_tail",
[KPF_HUGE] = "G:huge",
[KPF_UNEVICTABLE] = "u:unevictable",
+ [KPF_HWPOISON] = "X:hwpoison",
[KPF_NOPAGE] = "n:nopage",
+ [KPF_KSM] = "x:ksm",
[KPF_RESERVED] = "r:reserved",
[KPF_MLOCKED] = "m:mlocked",
@@ -152,9 +159,6 @@ static unsigned long opt_size[MAX_ADDR_RANGES];
static int nr_vmas;
static unsigned long pg_start[MAX_VMAS];
static unsigned long pg_end[MAX_VMAS];
-static unsigned long voffset;
-
-static int pagemap_fd;
#define MAX_BIT_FILTERS 64
static int nr_bit_filters;
@@ -163,9 +167,16 @@ static uint64_t opt_bits[MAX_BIT_FILTERS];
static int page_size;
-#define PAGES_BATCH (64 << 10) /* 64k pages */
+static int pagemap_fd;
static int kpageflags_fd;
+static int opt_hwpoison;
+static int opt_unpoison;
+
+static char *hwpoison_debug_fs = "/debug/hwpoison";
+static int hwpoison_inject_fd;
+static int hwpoison_forget_fd;
+
#define HASH_SHIFT 13
#define HASH_SIZE (1 << HASH_SHIFT)
#define HASH_MASK (HASH_SIZE - 1)
@@ -207,6 +218,74 @@ static void fatal(const char *x, ...)
exit(EXIT_FAILURE);
}
+int checked_open(const char *pathname, int flags)
+{
+ int fd = open(pathname, flags);
+
+ if (fd < 0) {
+ perror(pathname);
+ exit(EXIT_FAILURE);
+ }
+
+ return fd;
+}
+
+/*
+ * pagemap/kpageflags routines
+ */
+
+static unsigned long do_u64_read(int fd, char *name,
+ uint64_t *buf,
+ unsigned long index,
+ unsigned long count)
+{
+ long bytes;
+
+ if (index > ULONG_MAX / 8)
+ fatal("index overflow: %lu\n", index);
+
+ if (lseek(fd, index * 8, SEEK_SET) < 0) {
+ perror(name);
+ exit(EXIT_FAILURE);
+ }
+
+ bytes = read(fd, buf, count * 8);
+ if (bytes < 0) {
+ perror(name);
+ exit(EXIT_FAILURE);
+ }
+ if (bytes % 8)
+ fatal("partial read: %lu bytes\n", bytes);
+
+ return bytes / 8;
+}
+
+static unsigned long kpageflags_read(uint64_t *buf,
+ unsigned long index,
+ unsigned long pages)
+{
+ return do_u64_read(kpageflags_fd, PROC_KPAGEFLAGS, buf, index, pages);
+}
+
+static unsigned long pagemap_read(uint64_t *buf,
+ unsigned long index,
+ unsigned long pages)
+{
+ return do_u64_read(pagemap_fd, "/proc/pid/pagemap", buf, index, pages);
+}
+
+static unsigned long pagemap_pfn(uint64_t val)
+{
+ unsigned long pfn;
+
+ if (val & PM_PRESENT)
+ pfn = PM_PFRAME(val);
+ else
+ pfn = 0;
+
+ return pfn;
+}
+
/*
* page flag names
@@ -255,7 +334,8 @@ static char *page_flag_longname(uint64_t flags)
* page list and summary
*/
-static void show_page_range(unsigned long offset, uint64_t flags)
+static void show_page_range(unsigned long voffset,
+ unsigned long offset, uint64_t flags)
{
static uint64_t flags0;
static unsigned long voff;
@@ -281,7 +361,8 @@ static void show_page_range(unsigned long offset, uint64_t flags)
count = 1;
}
-static void show_page(unsigned long offset, uint64_t flags)
+static void show_page(unsigned long voffset,
+ unsigned long offset, uint64_t flags)
{
if (opt_pid)
printf("%lx\t", voffset);
@@ -362,6 +443,62 @@ static uint64_t well_known_flags(uint64_t flags)
return flags;
}
+static uint64_t kpageflags_flags(uint64_t flags)
+{
+ flags = expand_overloaded_flags(flags);
+
+ if (!opt_raw)
+ flags = well_known_flags(flags);
+
+ return flags;
+}
+
+/*
+ * page actions
+ */
+
+static void prepare_hwpoison_fd(void)
+{
+ char buf[100];
+
+ if (opt_hwpoison && !hwpoison_inject_fd) {
+ sprintf(buf, "%s/corrupt-pfn", hwpoison_debug_fs);
+ hwpoison_inject_fd = checked_open(buf, O_WRONLY);
+ }
+
+ if (opt_unpoison && !hwpoison_forget_fd) {
+ sprintf(buf, "%s/renew-pfn", hwpoison_debug_fs);
+ hwpoison_forget_fd = checked_open(buf, O_WRONLY);
+ }
+}
+
+static int hwpoison_page(unsigned long offset)
+{
+ char buf[100];
+ int len;
+
+ len = sprintf(buf, "0x%lx\n", offset);
+ len = write(hwpoison_inject_fd, buf, len);
+ if (len < 0) {
+ perror("hwpoison inject");
+ return len;
+ }
+ return 0;
+}
+
+static int unpoison_page(unsigned long offset)
+{
+ char buf[100];
+ int len;
+
+ len = sprintf(buf, "0x%lx\n", offset);
+ len = write(hwpoison_forget_fd, buf, len);
+ if (len < 0) {
+ perror("hwpoison forget");
+ return len;
+ }
+ return 0;
+}
/*
* page frame walker
@@ -394,104 +531,83 @@ static int hash_slot(uint64_t flags)
exit(EXIT_FAILURE);
}
-static void add_page(unsigned long offset, uint64_t flags)
+static void add_page(unsigned long voffset,
+ unsigned long offset, uint64_t flags)
{
- flags = expand_overloaded_flags(flags);
-
- if (!opt_raw)
- flags = well_known_flags(flags);
+ flags = kpageflags_flags(flags);
if (!bit_mask_ok(flags))
return;
+ if (opt_hwpoison)
+ hwpoison_page(offset);
+ if (opt_unpoison)
+ unpoison_page(offset);
+
if (opt_list == 1)
- show_page_range(offset, flags);
+ show_page_range(voffset, offset, flags);
else if (opt_list == 2)
- show_page(offset, flags);
+ show_page(voffset, offset, flags);
nr_pages[hash_slot(flags)]++;
total_pages++;
}
-static void walk_pfn(unsigned long index, unsigned long count)
+#define KPAGEFLAGS_BATCH (64 << 10) /* 64k pages */
+static void walk_pfn(unsigned long voffset,
+ unsigned long index,
+ unsigned long count)
{
+ uint64_t buf[KPAGEFLAGS_BATCH];
unsigned long batch;
- unsigned long n;
+ unsigned long pages;
unsigned long i;
- if (index > ULONG_MAX / KPF_BYTES)
- fatal("index overflow: %lu\n", index);
-
- lseek(kpageflags_fd, index * KPF_BYTES, SEEK_SET);
-
while (count) {
- uint64_t kpageflags_buf[KPF_BYTES * PAGES_BATCH];
-
- batch = min_t(unsigned long, count, PAGES_BATCH);
- n = read(kpageflags_fd, kpageflags_buf, batch * KPF_BYTES);
- if (n == 0)
+ batch = min_t(unsigned long, count, KPAGEFLAGS_BATCH);
+ pages = kpageflags_read(buf, index, batch);
+ if (pages == 0)
break;
- if (n < 0) {
- perror(PROC_KPAGEFLAGS);
- exit(EXIT_FAILURE);
- }
- if (n % KPF_BYTES != 0)
- fatal("partial read: %lu bytes\n", n);
- n = n / KPF_BYTES;
+ for (i = 0; i < pages; i++)
+ add_page(voffset + i, index + i, buf[i]);
- for (i = 0; i < n; i++)
- add_page(index + i, kpageflags_buf[i]);
-
- index += batch;
- count -= batch;
+ index += pages;
+ count -= pages;
}
}
-
-#define PAGEMAP_BATCH 4096
-static unsigned long task_pfn(unsigned long pgoff)
+#define PAGEMAP_BATCH (64 << 10)
+static void walk_vma(unsigned long index, unsigned long count)
{
- static uint64_t buf[PAGEMAP_BATCH];
- static unsigned long start;
- static long count;
- uint64_t pfn;
+ uint64_t buf[PAGEMAP_BATCH];
+ unsigned long batch;
+ unsigned long pages;
+ unsigned long pfn;
+ unsigned long i;
- if (pgoff < start || pgoff >= start + count) {
- if (lseek64(pagemap_fd,
- (uint64_t)pgoff * PM_ENTRY_BYTES,
- SEEK_SET) < 0) {
- perror("pagemap seek");
- exit(EXIT_FAILURE);
- }
- count = read(pagemap_fd, buf, sizeof(buf));
- if (count == 0)
- return 0;
- if (count < 0) {
- perror("pagemap read");
- exit(EXIT_FAILURE);
- }
- if (count % PM_ENTRY_BYTES) {
- fatal("pagemap read not aligned.\n");
- exit(EXIT_FAILURE);
- }
- count /= PM_ENTRY_BYTES;
- start = pgoff;
- }
+ while (count) {
+ batch = min_t(unsigned long, count, PAGEMAP_BATCH);
+ pages = pagemap_read(buf, index, batch);
+ if (pages == 0)
+ break;
- pfn = buf[pgoff - start];
- if (pfn & PM_PRESENT)
- pfn = PM_PFRAME(pfn);
- else
- pfn = 0;
+ for (i = 0; i < pages; i++) {
+ pfn = pagemap_pfn(buf[i]);
+ if (pfn)
+ walk_pfn(index + i, pfn, 1);
+ }
- return pfn;
+ index += pages;
+ count -= pages;
+ }
}
static void walk_task(unsigned long index, unsigned long count)
{
- int i = 0;
const unsigned long end = index + count;
+ unsigned long start;
+ int i = 0;
while (index < end) {
@@ -501,15 +617,11 @@ static void walk_task(unsigned long index, unsigned long count)
if (pg_start[i] >= end)
return;
- voffset = max_t(unsigned long, pg_start[i], index);
- index = min_t(unsigned long, pg_end[i], end);
+ start = max_t(unsigned long, pg_start[i], index);
+ index = min_t(unsigned long, pg_end[i], end);
- assert(voffset < index);
- for (; voffset < index; voffset++) {
- unsigned long pfn = task_pfn(voffset);
- if (pfn)
- walk_pfn(pfn, 1);
- }
+ assert(start < index);
+ walk_vma(start, index - start);
}
}
@@ -527,18 +639,14 @@ static void walk_addr_ranges(void)
{
int i;
- kpageflags_fd = open(PROC_KPAGEFLAGS, O_RDONLY);
- if (kpageflags_fd < 0) {
- perror(PROC_KPAGEFLAGS);
- exit(EXIT_FAILURE);
- }
+ kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY);
if (!nr_addr_ranges)
add_addr_range(0, ULONG_MAX);
for (i = 0; i < nr_addr_ranges; i++)
if (!opt_pid)
- walk_pfn(opt_offset[i], opt_size[i]);
+ walk_pfn(0, opt_offset[i], opt_size[i]);
else
walk_task(opt_offset[i], opt_size[i]);
@@ -575,6 +683,8 @@ static void usage(void)
" -l|--list Show page details in ranges\n"
" -L|--list-each Show page details one by one\n"
" -N|--no-summary Don't show summay info\n"
+" -X|--hwpoison hwpoison pages\n"
+" -x|--unpoison unpoison pages\n"
" -h|--help Show this usage message\n"
"addr-spec:\n"
" N one page at offset N (unit: pages)\n"
@@ -624,11 +734,7 @@ static void parse_pid(const char *str)
opt_pid = parse_number(str);
sprintf(buf, "/proc/%d/pagemap", opt_pid);
- pagemap_fd = open(buf, O_RDONLY);
- if (pagemap_fd < 0) {
- perror(buf);
- exit(EXIT_FAILURE);
- }
+ pagemap_fd = checked_open(buf, O_RDONLY);
sprintf(buf, "/proc/%d/maps", opt_pid);
file = fopen(buf, "r");
@@ -788,6 +894,8 @@ static struct option opts[] = {
{ "list" , 0, NULL, 'l' },
{ "list-each" , 0, NULL, 'L' },
{ "no-summary", 0, NULL, 'N' },
+ { "hwpoison" , 0, NULL, 'X' },
+ { "unpoison" , 0, NULL, 'x' },
{ "help" , 0, NULL, 'h' },
{ NULL , 0, NULL, 0 }
};
@@ -799,7 +907,7 @@ int main(int argc, char *argv[])
page_size = getpagesize();
while ((c = getopt_long(argc, argv,
- "rp:f:a:b:lLNh", opts, NULL)) != -1) {
+ "rp:f:a:b:lLNXxh", opts, NULL)) != -1) {
switch (c) {
case 'r':
opt_raw = 1;
@@ -825,6 +933,14 @@ int main(int argc, char *argv[])
case 'N':
opt_no_summary = 1;
break;
+ case 'X':
+ opt_hwpoison = 1;
+ prepare_hwpoison_fd();
+ break;
+ case 'x':
+ opt_unpoison = 1;
+ prepare_hwpoison_fd();
+ break;
case 'h':
usage();
exit(0);
@@ -844,7 +960,7 @@ int main(int argc, char *argv[])
walk_addr_ranges();
if (opt_list == 1)
- show_page_range(0, 0); /* drain the buffer */
+ show_page_range(0, 0, 0); /* drain the buffer */
if (opt_no_summary)
return 0;
diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt
index 600a304a828c..df09b9650a81 100644
--- a/Documentation/vm/pagemap.txt
+++ b/Documentation/vm/pagemap.txt
@@ -57,7 +57,9 @@ There are three components to pagemap:
16. COMPOUND_TAIL
16. HUGE
18. UNEVICTABLE
+ 19. HWPOISON
20. NOPAGE
+ 21. KSM
Short descriptions to the page flags:
@@ -86,9 +88,15 @@ Short descriptions to the page flags:
17. HUGE
this is an integral part of a HugeTLB page
+19. HWPOISON
+ hardware detected memory corruption on this page: don't touch the data!
+
20. NOPAGE
no page frame exists at the requested address
+21. KSM
+ identical memory pages dynamically shared between one or more processes
+
[IO related page flags]
1. ERROR IO error occurred
3. UPTODATE page has up-to-date data
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 09a2028bab7f..6b5de7a29d6e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -577,6 +577,11 @@ M: Mike Rapoport <mike@compulab.co.il>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
+ARM/CONTEC MICRO9 MACHINE SUPPORT
+M: Hubert Feurstein <hubert.feurstein@contec.at>
+S: Maintained
+F: arch/arm/mach-ep93xx/micro9.c
+
ARM/CORGI MACHINE SUPPORT
M: Richard Purdie <rpurdie@rpsys.net>
S: Maintained
@@ -1086,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
@@ -1231,6 +1235,13 @@ L: netdev@vger.kernel.org
S: Supported
F: drivers/net/tg3.*
+BROCADE BFA FC SCSI DRIVER
+P: Jing Huang
+M: huangj@brocade.com
+L: linux-scsi@vger.kernel.org
+S: Supported
+F: drivers/scsi/bfa/
+
BSG (block layer generic sg v4 driver)
M: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
L: linux-scsi@vger.kernel.org
@@ -1468,6 +1479,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
@@ -1778,6 +1790,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/
@@ -2058,7 +2083,7 @@ S: Maintained
F: fs/*
FINTEK F75375S HARDWARE MONITOR AND FAN CONTROLLER DRIVER
-M: Riku Voipio <riku.vipio@iki.fi>
+M: Riku Voipio <riku.voipio@iki.fi>
L: lm-sensors@lm-sensors.org
S: Maintained
F: drivers/hwmon/f75375s.c
@@ -2603,6 +2628,7 @@ L: linux1394-devel@lists.sourceforge.net
W: http://www.linux1394.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
S: Maintained
+F: Documentation/debugging-via-ohci1394.txt
F: drivers/ieee1394/
IEEE 1394 RAW I/O DRIVER
@@ -3643,10 +3669,18 @@ F: Documentation/blockdev/nbd.txt
F: drivers/block/nbd.c
F: include/linux/nbd.h
+NETWORK DROP MONITOR
+M: Neil Horman <nhorman@tuxdriver.com>
+L: netdev@vger.kernel.org
+S: Maintained
+W: https://fedorahosted.org/dropwatch/
+F: net/core/drop_monitor.c
+
NETWORKING [GENERAL]
M: "David S. Miller" <davem@davemloft.net>
L: netdev@vger.kernel.org
W: http://www.linuxfoundation.org/en/Net
+W: http://patchwork.ozlabs.org/project/netdev/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6.git
S: Maintained
F: net/
@@ -3973,6 +4007,7 @@ F: drivers/block/paride/
PARISC ARCHITECTURE
M: Kyle McMartin <kyle@mcmartin.ca>
M: Helge Deller <deller@gmx.de>
+M: "James E.J. Bottomley" <jejb@parisc-linux.org>
L: linux-parisc@vger.kernel.org
W: http://www.parisc-linux.org/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6.git
@@ -4056,6 +4091,13 @@ M: Peter Zijlstra <a.p.zijlstra@chello.nl>
M: Paul Mackerras <paulus@samba.org>
M: Ingo Molnar <mingo@elte.hu>
S: Supported
+F: kernel/perf_event.c
+F: include/linux/perf_event.h
+F: arch/*/*/kernel/perf_event.c
+F: arch/*/include/asm/perf_event.h
+F: arch/*/lib/perf_event.c
+F: arch/*/kernel/perf_callchain.c
+F: tools/perf/
PERSONALITY HANDLING
M: Christoph Hellwig <hch@infradead.org>
@@ -4638,6 +4680,14 @@ F: drivers/ata/
F: include/linux/ata.h
F: include/linux/libata.h
+SERVER ENGINES 10Gbps iSCSI - BladeEngine 2 DRIVER
+P: Jayamohan Kallickal
+M: jayamohank@serverengines.com
+L: linux-scsi@vger.kernel.org
+W: http://www.serverengines.com
+S: Supported
+F: drivers/scsi/be2iscsi/
+
SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER
M: Sathya Perla <sathyap@serverengines.com>
M: Subbu Seetharaman <subbus@serverengines.com>
@@ -5628,6 +5678,13 @@ S: Maintained
F: drivers/vlynq/vlynq.c
F: include/linux/vlynq.h
+VMWARE VMXNET3 ETHERNET DRIVER
+M: Shreyas Bhatewara <sbhatewara@vmware.com>
+M: VMware, Inc. <pv-drivers@vmware.com>
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/vmxnet3/
+
VOLTAGE AND CURRENT REGULATOR FRAMEWORK
M: Liam Girdwood <lrg@slimlogic.co.uk>
M: Mark Brown <broonie@opensource.wolfsonmicro.com>
diff --git a/Makefile b/Makefile
index e50569ab5fe8..85b73a444838 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 32
-EXTRAVERSION = -rc3
+EXTRAVERSION = -rc4
NAME = Man-Eating Seals of Antiquity
# *DOCUMENTATION*
@@ -179,46 +179,9 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
# Alternatively CROSS_COMPILE can be set in the environment.
# Default value for CROSS_COMPILE is not to prefix executables
# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
-#
-# To force ARCH and CROSS_COMPILE settings include kernel.* files
-# in the kernel tree - do not patch this file.
export KBUILD_BUILDHOST := $(SUBARCH)
-
-# Kbuild save the ARCH and CROSS_COMPILE setting in kernel.* files.
-# Restore these settings and check that user did not specify
-# conflicting values.
-
-saved_arch := $(shell cat include/generated/kernel.arch 2> /dev/null)
-saved_cross := $(shell cat include/generated/kernel.cross 2> /dev/null)
-
-ifneq ($(CROSS_COMPILE),)
- ifneq ($(saved_cross),)
- ifneq ($(CROSS_COMPILE),$(saved_cross))
- $(error CROSS_COMPILE changed from \
- "$(saved_cross)" to \
- to "$(CROSS_COMPILE)". \
- Use "make mrproper" to fix it up)
- endif
- endif
-else
- CROSS_COMPILE := $(saved_cross)
-endif
-
-ifneq ($(ARCH),)
- ifneq ($(saved_arch),)
- ifneq ($(saved_arch),$(ARCH))
- $(error ARCH changed from \
- "$(saved_arch)" to "$(ARCH)". \
- Use "make mrproper" to fix it up)
- endif
- endif
-else
- ifneq ($(saved_arch),)
- ARCH := $(saved_arch)
- else
- ARCH := $(SUBARCH)
- endif
-endif
+ARCH ?= $(SUBARCH)
+CROSS_COMPILE ?=
# Architecture as present in compile.h
UTS_MACHINE := $(ARCH)
@@ -372,9 +335,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) \
+ $(if $(KBUILD_SRC), -I$(srctree)/include) \
-I$(srctree)/arch/$(hdr-arch)/include \
- -include include/linux/autoconf.h
+ -include include/generated/autoconf.h
KBUILD_CPPFLAGS := -D__KERNEL__
@@ -483,11 +446,6 @@ ifeq ($(config-targets),1)
include $(srctree)/arch/$(SRCARCH)/Makefile
export KBUILD_DEFCONFIG KBUILD_KCONFIG
-# save ARCH & CROSS_COMPILE settings
-$(shell mkdir -p include/generated && \
- echo $(ARCH) > include/generated/kernel.arch && \
- echo $(CROSS_COMPILE) > include/generated/kernel.cross)
-
config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p include/linux include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
@@ -534,17 +492,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)
@@ -987,7 +946,7 @@ include/config/kernel.release: include/config/auto.conf FORCE
# Things we need to do before we recursively start building the kernel
# or the modules are listed in "prepare".
# A multi level approach is used. prepareN is processed before prepareN-1.
-# archprepare is used in arch Makefiles and when processed asm symlink,
+# archprepare is used in arch Makefiles when
# version.h and scripts_basic is processed / created.
# Listed in dependency order
@@ -996,7 +955,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'
@@ -1005,17 +963,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
@@ -1027,42 +981,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
# ---------------------------------------------------------------------------
@@ -1087,7 +1005,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
@@ -1235,11 +1153,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/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/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/da830_omapl137_defconfig
deleted file mode 100644
index 7c8e38f5c5ab..000000000000
--- a/arch/arm/configs/da830_omapl137_defconfig
+++ /dev/null
@@ -1,1254 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.30-rc2-davinci1
-# Wed May 13 15:33:29 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
-CONFIG_LOCKDEP_SUPPORT=y
-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_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"
-
-#
-# 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_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_POSIX_MQUEUE_SYSCTL=y
-# CONFIG_BSD_PROCESS_ACCT 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_TRACE is not set
-# CONFIG_PREEMPT_RCU_TRACE is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_GROUP_SCHED=y
-CONFIG_FAIR_GROUP_SCHED=y
-# CONFIG_RT_GROUP_SCHED is not set
-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_RELAY is not set
-# CONFIG_NAMESPACES is not set
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-CONFIG_RD_GZIP=y
-# CONFIG_RD_BZIP2 is not set
-# CONFIG_RD_LZMA is not set
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL=y
-CONFIG_ANON_INODES=y
-CONFIG_EMBEDDED=y
-CONFIG_UID16=y
-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
-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_VM_EVENT_COUNTERS=y
-CONFIG_SLUB_DEBUG=y
-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
-CONFIG_HAVE_KRETPROBES=y
-CONFIG_HAVE_CLK=y
-# CONFIG_SLOW_WORK is not set
-CONFIG_HAVE_GENERIC_DMA_COHERENT=y
-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=y
-CONFIG_MODVERSIONS=y
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_BLK_DEV_INTEGRITY is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-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
-
-#
-# System Type
-#
-# 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_EBSA110 is not set
-# CONFIG_ARCH_EP93XX is not set
-# CONFIG_ARCH_GEMINI is not set
-# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_NETX is not set
-# CONFIG_ARCH_H720X is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_IOP13XX is not set
-# CONFIG_ARCH_IOP32X is not set
-# CONFIG_ARCH_IOP33X is not set
-# CONFIG_ARCH_IXP23XX is not set
-# CONFIG_ARCH_IXP2000 is not set
-# 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_PNX4008 is not set
-# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_MMP 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_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
-
-#
-# 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_CP15=y
-CONFIG_CPU_CP15_MMU=y
-
-#
-# Processor Features
-#
-CONFIG_ARM_THUMB=y
-# 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_COMMON_CLKDEV=y
-
-#
-# Bus support
-#
-# CONFIG_PCI_SYSCALL is not set
-# CONFIG_ARCH_SUPPORTS_MSI is not set
-# CONFIG_PCCARD is not set
-
-#
-# Kernel Features
-#
-CONFIG_TICK_ONESHOT=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
-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_AEABI=y
-# CONFIG_OABI_COMPAT is not set
-CONFIG_ARCH_FLATMEM_HAS_HOLES=y
-# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
-# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
-# CONFIG_HIGHMEM is not set
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_PAGEFLAGS_EXTENDED=y
-CONFIG_SPLIT_PTLOCK_CPUS=4096
-# CONFIG_PHYS_ADDR_T_64BIT is not set
-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_LEDS=y
-# CONFIG_LEDS_CPU is not set
-CONFIG_ALIGNMENT_TRAP=y
-
-#
-# Boot options
-#
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE=""
-# CONFIG_XIP_KERNEL is not set
-# CONFIG_KEXEC is not set
-
-#
-# CPU Power Management
-#
-# CONFIG_CPU_IDLE is not set
-
-#
-# Floating point emulation
-#
-
-#
-# At least one emulation must be selected
-#
-# CONFIG_VFP is not set
-
-#
-# Userspace binary formats
-#
-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
-
-#
-# Power management options
-#
-# CONFIG_PM is not set
-CONFIG_ARCH_SUSPEND_POSSIBLE=y
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# 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_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_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# 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_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
-# CONFIG_INET_LRO is not set
-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=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_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_IP_DCCP is not set
-# CONFIG_IP_SCTP 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_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_NET_SCHED is not set
-# CONFIG_DCB is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN 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 is not set
-# 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_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-# 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_PARPORT is not set
-CONFIG_BLK_DEV=y
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=1
-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_MISC_DEVICES=y
-# CONFIG_ICS932S401 is not set
-# CONFIG_ENCLOSURE_SERVICES is not set
-# CONFIG_ISL29003 is not set
-# CONFIG_C2PORT is not set
-
-#
-# EEPROM support
-#
-CONFIG_EEPROM_AT24=y
-# CONFIG_EEPROM_LEGACY is not set
-# CONFIG_EEPROM_93CX6 is not set
-CONFIG_HAVE_IDE=y
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=m
-CONFIG_SCSI_DMA=y
-# CONFIG_SCSI_TGT is not set
-# CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=m
-# 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
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_LIBFC is not set
-# CONFIG_LIBFCOE is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_DH is not set
-# CONFIG_SCSI_OSD_INITIATOR is not set
-# 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_VETH is not set
-CONFIG_PHYLIB=y
-
-#
-# MII PHY device drivers
-#
-# CONFIG_MARVELL_PHY is not set
-# CONFIG_DAVICOM_PHY is not set
-# CONFIG_QSEMI_PHY is not set
-CONFIG_LXT_PHY=y
-# CONFIG_CICADA_PHY is not set
-# CONFIG_VITESSE_PHY is not set
-# CONFIG_SMSC_PHY is not set
-# CONFIG_BROADCOM_PHY is not set
-# 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=y
-# 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_ETHOC is not set
-# CONFIG_SMC911X is not set
-# CONFIG_SMSC911X is not set
-# CONFIG_DNET 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_B44 is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-
-#
-# Enable WiMAX (Networking options) to see the WiMAX drivers
-#
-# 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_ISDN 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=m
-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
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=m
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-CONFIG_KEYBOARD_XTKBD=m
-# CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_STOWAWAY is not set
-CONFIG_KEYBOARD_GPIO=y
-# 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_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_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_TOUCHIT213 is not set
-# CONFIG_TOUCHSCREEN_TSC2007 is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=y
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_CONSOLE_TRANSLATIONS=y
-# CONFIG_VT_CONSOLE is not set
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-CONFIG_DEVKMEM=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-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
-
-#
-# Non-8250 serial port support
-#
-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_IPMI_HANDLER is not set
-CONFIG_HW_RANDOM=m
-# 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_CHARDEV=y
-CONFIG_I2C_HELPER_AUTO=y
-
-#
-# I2C Hardware Bus support
-#
-
-#
-# I2C system bus drivers (mostly embedded / system-on-chip)
-#
-CONFIG_I2C_DAVINCI=y
-# CONFIG_I2C_GPIO is not set
-# 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
-
-#
-# 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_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_ARCH_REQUIRE_GPIOLIB=y
-CONFIG_GPIOLIB=y
-# CONFIG_DEBUG_GPIO is not set
-# CONFIG_GPIO_SYSFS is not set
-
-#
-# Memory mapped GPIO expanders:
-#
-
-#
-# I2C GPIO expanders:
-#
-# CONFIG_GPIO_MAX732X is not set
-# CONFIG_GPIO_PCA953X is not set
-CONFIG_GPIO_PCF857X=m
-
-#
-# PCI GPIO expanders:
-#
-
-#
-# SPI 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
-
-#
-# Watchdog Device Drivers
-#
-# CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_DAVINCI_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_MFD_ASIC3 is not set
-# CONFIG_HTC_EGPIO is not set
-# CONFIG_HTC_PASIC3 is not set
-# CONFIG_TPS65010 is not set
-# CONFIG_TWL4030_CORE 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_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
-
-#
-# Graphics support
-#
-# CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-
-#
-# Console display driver support
-#
-# 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_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_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_PXA27X is not set
-# CONFIG_USB_GADGET_S3C2410 is not set
-# CONFIG_USB_GADGET_IMX 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_DUMMY_HCD is not set
-# CONFIG_USB_ZERO is not set
-# CONFIG_USB_ETH 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
-# CONFIG_MEMSTICK is not set
-# CONFIG_ACCESSIBILITY is not set
-# CONFIG_NEW_LEDS 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
-# CONFIG_STAGING is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# 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_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_OCFS2_FS is not set
-# CONFIG_BTRFS_FS is not set
-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 is not set
-# CONFIG_UDF_FS is not set
-
-#
-# 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_SYSCTL=y
-CONFIG_PROC_PAGE_MONITOR=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL 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 is not set
-# CONFIG_HFSPLUS_FS is not set
-# 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=m
-# 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_ROOT_NFS=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V3_ACL is not set
-# CONFIG_NFSD_V4 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_RPCSEC_GSS_SPKM3 is not set
-CONFIG_SMB_FS=m
-# CONFIG_SMB_NLS_DEFAULT is not set
-# CONFIG_CIFS 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 is not set
-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 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# 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_ISO8859_1=y
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-CONFIG_NLS_UTF8=m
-# CONFIG_DLM is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_WARN_DEPRECATED=y
-CONFIG_ENABLE_MUST_CHECK=y
-CONFIG_FRAME_WARN=1024
-# CONFIG_MAGIC_SYSRQ 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 is not set
-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_PREEMPT=y
-CONFIG_DEBUG_RT_MUTEXES=y
-CONFIG_DEBUG_PI_LIST=y
-# 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_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_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_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_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_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_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_DYNAMIC_DEBUG is not set
-# CONFIG_SAMPLES is not set
-CONFIG_HAVE_ARCH_KGDB=y
-# CONFIG_KGDB is not set
-CONFIG_ARM_UNWIND=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_ERRORS=y
-# CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_LL 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_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
-# CONFIG_CRYPTO_NULL is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_AUTHENC is not set
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Authenticated Encryption with Associated Data
-#
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_SEQIV is not set
-
-#
-# Block modes
-#
-# CONFIG_CRYPTO_CBC is not set
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_CTS is not set
-# CONFIG_CRYPTO_ECB is not set
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_PCBC is not set
-# CONFIG_CRYPTO_XTS is not set
-
-#
-# Hash modes
-#
-# CONFIG_CRYPTO_HMAC is not set
-# CONFIG_CRYPTO_XCBC is not set
-
-#
-# Digest
-#
-# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_MD4 is not set
-# CONFIG_CRYPTO_MD5 is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# 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 is not set
-# CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_WP512 is not set
-
-#
-# Ciphers
-#
-# CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_ARC4 is not set
-# CONFIG_CRYPTO_BLOWFISH is not set
-# 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_FCRYPT is not set
-# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_SALSA20 is not set
-# CONFIG_CRYPTO_SEED is not set
-# CONFIG_CRYPTO_SERPENT is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-
-#
-# Compression
-#
-# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_ZLIB is not set
-# CONFIG_CRYPTO_LZO is not set
-
-#
-# Random Number Generation
-#
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-# CONFIG_CRYPTO_HW is not set
-# CONFIG_BINARY_PRINTF is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-CONFIG_GENERIC_FIND_LAST_BIT=y
-CONFIG_CRC_CCITT=m
-# CONFIG_CRC16 is not set
-CONFIG_CRC_T10DIF=m
-# CONFIG_CRC_ITU_T is not set
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
-CONFIG_DECOMPRESS_GZIP=y
-CONFIG_GENERIC_ALLOCATOR=y
-CONFIG_HAS_IOMEM=y
-CONFIG_HAS_IOPORT=y
-CONFIG_HAS_DMA=y
-CONFIG_NLATTR=y
diff --git a/arch/arm/configs/da850_omapl138_defconfig b/arch/arm/configs/da8xx_omapl_defconfig
index 842a70b079bf..bfd5121ba2b4 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-rc2-davinci1
+# Mon Sep 28 16:00:25 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,13 @@ 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_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 +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
@@ -62,8 +60,7 @@ 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_V2 is not set
# CONFIG_RELAY is not set
# CONFIG_NAMESPACES is not set
CONFIG_BLK_DEV_INITRD=y
@@ -80,7 +77,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 +89,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 +100,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 +122,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 +143,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 +167,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 +200,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,6 +208,8 @@ CONFIG_ARCH_DAVINCI_DA8XX=y
#
# DaVinci Board Type
#
+CONFIG_MACH_DAVINCI_DA830_EVM=y
+# CONFIG_DA830_UI is not set
CONFIG_MACH_DAVINCI_DA850_EVM=y
CONFIG_DAVINCI_MUX=y
# CONFIG_DAVINCI_MUX_DEBUG is not set
@@ -227,7 +238,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_OUTER_CACHE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
CONFIG_COMMON_CLKDEV=y
#
@@ -248,11 +259,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 +280,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
@@ -401,6 +415,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 +430,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 +456,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 +477,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 +489,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 +513,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 +537,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 +567,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 +581,10 @@ 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_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 +600,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 +624,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 +656,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 +705,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 +717,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 +738,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
@@ -746,11 +772,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,24 +811,12 @@ 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
@@ -834,6 +851,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 +864,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 +873,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 +904,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 +973,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 +1068,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 +1086,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 +1107,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 +1156,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 +1187,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/omap3_beagle_defconfig b/arch/arm/configs/omap3_beagle_defconfig
index 357d4021e2d0..b3c8cce0f8fb 100644
--- a/arch/arm/configs/omap3_beagle_defconfig
+++ b/arch/arm/configs/omap3_beagle_defconfig
@@ -969,7 +969,6 @@ CONFIG_USB_ETH_RNDIS=y
#
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
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/bitops.h b/arch/arm/include/asm/bitops.h
index 63a481fbbed4..338ff19ae447 100644
--- a/arch/arm/include/asm/bitops.h
+++ b/arch/arm/include/asm/bitops.h
@@ -84,7 +84,7 @@ ____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p)
*p = res | mask;
raw_local_irq_restore(flags);
- return res & mask;
+ return (res & mask) != 0;
}
static inline int
@@ -101,7 +101,7 @@ ____atomic_test_and_clear_bit(unsigned int bit, volatile unsigned long *p)
*p = res & ~mask;
raw_local_irq_restore(flags);
- return res & mask;
+ return (res & mask) != 0;
}
static inline int
@@ -118,7 +118,7 @@ ____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p)
*p = res ^ mask;
raw_local_irq_restore(flags);
- return res & mask;
+ return (res & mask) != 0;
}
#include <asm-generic/bitops/non-atomic.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/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/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/kernel/time.c b/arch/arm/kernel/time.c
index 4cdc4a0bd02d..d38cdf2c8276 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -21,6 +21,7 @@
#include <linux/interrupt.h>
#include <linux/time.h>
#include <linux/init.h>
+#include <linux/sched.h>
#include <linux/smp.h>
#include <linux/timex.h>
#include <linux/errno.h>
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 467b69ed1021..f838f36eb702 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -45,21 +45,21 @@ static int __init user_debug_setup(char *str)
__setup("user_debug=", user_debug_setup);
#endif
-static void dump_mem(const char *str, unsigned long bottom, unsigned long top);
+static void dump_mem(const char *, const char *, unsigned long, unsigned long);
void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame)
{
#ifdef CONFIG_KALLSYMS
- printk("[<%08lx>] ", where);
- print_symbol("(%s) ", where);
- printk("from [<%08lx>] ", from);
- print_symbol("(%s)\n", from);
+ char sym1[KSYM_SYMBOL_LEN], sym2[KSYM_SYMBOL_LEN];
+ sprint_symbol(sym1, where);
+ sprint_symbol(sym2, from);
+ printk("[<%08lx>] (%s) from [<%08lx>] (%s)\n", where, sym1, from, sym2);
#else
printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
#endif
if (in_exception_text(where))
- dump_mem("Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
+ dump_mem("", "Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
}
#ifndef CONFIG_ARM_UNWIND
@@ -81,9 +81,10 @@ static int verify_stack(unsigned long sp)
/*
* Dump out the contents of some memory nicely...
*/
-static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
+static void dump_mem(const char *lvl, const char *str, unsigned long bottom,
+ unsigned long top)
{
- unsigned long p = bottom & ~31;
+ unsigned long first;
mm_segment_t fs;
int i;
@@ -95,33 +96,37 @@ static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
fs = get_fs();
set_fs(KERNEL_DS);
- printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
+ printk("%s%s(0x%08lx to 0x%08lx)\n", lvl, str, bottom, top);
- for (p = bottom & ~31; p < top;) {
- printk("%04lx: ", p & 0xffff);
+ for (first = bottom & ~31; first < top; first += 32) {
+ unsigned long p;
+ char str[sizeof(" 12345678") * 8 + 1];
- for (i = 0; i < 8; i++, p += 4) {
- unsigned int val;
+ memset(str, ' ', sizeof(str));
+ str[sizeof(str) - 1] = '\0';
- if (p < bottom || p >= top)
- printk(" ");
- else {
- __get_user(val, (unsigned long *)p);
- printk("%08x ", val);
+ for (p = first, i = 0; i < 8 && p < top; i++, p += 4) {
+ if (p >= bottom && p < top) {
+ unsigned long val;
+ if (__get_user(val, (unsigned long *)p) == 0)
+ sprintf(str + i * 9, " %08lx", val);
+ else
+ sprintf(str + i * 9, " ????????");
}
}
- printk ("\n");
+ printk("%s%04lx:%s\n", lvl, first & 0xffff, str);
}
set_fs(fs);
}
-static void dump_instr(struct pt_regs *regs)
+static void dump_instr(const char *lvl, struct pt_regs *regs)
{
unsigned long addr = instruction_pointer(regs);
const int thumb = thumb_mode(regs);
const int width = thumb ? 4 : 8;
mm_segment_t fs;
+ char str[sizeof("00000000 ") * 5 + 2 + 1], *p = str;
int i;
/*
@@ -132,7 +137,6 @@ static void dump_instr(struct pt_regs *regs)
fs = get_fs();
set_fs(KERNEL_DS);
- printk("Code: ");
for (i = -4; i < 1; i++) {
unsigned int val, bad;
@@ -142,13 +146,14 @@ static void dump_instr(struct pt_regs *regs)
bad = __get_user(val, &((u32 *)addr)[i]);
if (!bad)
- printk(i == 0 ? "(%0*x) " : "%0*x ", width, val);
+ p += sprintf(p, i == 0 ? "(%0*x) " : "%0*x ",
+ width, val);
else {
- printk("bad PC value.");
+ p += sprintf(p, "bad PC value");
break;
}
}
- printk("\n");
+ printk("%sCode: %s\n", lvl, str);
set_fs(fs);
}
@@ -224,18 +229,19 @@ static void __die(const char *str, int err, struct thread_info *thread, struct p
struct task_struct *tsk = thread->task;
static int die_counter;
- printk("Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n",
+ printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n",
str, err, ++die_counter);
+ sysfs_printk_last_file();
print_modules();
__show_regs(regs);
- printk("Process %s (pid: %d, stack limit = 0x%p)\n",
- tsk->comm, task_pid_nr(tsk), thread + 1);
+ printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)\n",
+ TASK_COMM_LEN, tsk->comm, task_pid_nr(tsk), thread + 1);
if (!user_mode(regs) || in_interrupt()) {
- dump_mem("Stack: ", regs->ARM_sp,
+ dump_mem(KERN_EMERG, "Stack: ", regs->ARM_sp,
THREAD_SIZE + (unsigned long)task_stack_page(tsk));
dump_backtrace(regs, tsk);
- dump_instr(regs);
+ dump_instr(KERN_EMERG, regs);
}
}
@@ -250,13 +256,14 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
oops_enter();
- console_verbose();
spin_lock_irq(&die_lock);
+ console_verbose();
bust_spinlocks(1);
__die(str, err, thread, regs);
bust_spinlocks(0);
add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock);
+ oops_exit();
if (in_interrupt())
panic("Fatal exception in interrupt");
@@ -264,7 +271,6 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
if (panic_on_oops)
panic("Fatal exception");
- oops_exit();
do_exit(SIGSEGV);
}
@@ -349,7 +355,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
if (user_debug & UDBG_UNDEFINED) {
printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
current->comm, task_pid_nr(current), pc);
- dump_instr(regs);
+ dump_instr(KERN_INFO, regs);
}
#endif
@@ -400,7 +406,7 @@ static int bad_syscall(int n, struct pt_regs *regs)
if (user_debug & UDBG_SYSCALL) {
printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n",
task_pid_nr(current), current->comm, n);
- dump_instr(regs);
+ dump_instr(KERN_ERR, regs);
}
#endif
@@ -579,7 +585,7 @@ asmlinkage int arm_syscall(int no, struct pt_regs *regs)
if (user_debug & UDBG_SYSCALL) {
printk("[%d] %s: arm syscall %d\n",
task_pid_nr(current), current->comm, no);
- dump_instr(regs);
+ dump_instr("", regs);
if (user_mode(regs)) {
__show_regs(regs);
c_backtrace(regs->ARM_fp, processor_mode(regs));
@@ -656,7 +662,7 @@ baddataabort(int code, unsigned long instr, struct pt_regs *regs)
if (user_debug & UDBG_BADABORT) {
printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n",
task_pid_nr(current), current->comm, code, instr);
- dump_instr(regs);
+ dump_instr(KERN_ERR, regs);
show_pte(current->mm, addr);
}
#endif
diff --git a/arch/arm/mach-bcmring/core.c b/arch/arm/mach-bcmring/core.c
index 4b4f69251b31..e590bbe0a7b4 100644
--- a/arch/arm/mach-bcmring/core.c
+++ b/arch/arm/mach-bcmring/core.c
@@ -271,12 +271,12 @@ static struct irqaction bcmring_timer_irq = {
.handler = bcmring_timer_interrupt,
};
-static cycle_t bcmring_get_cycles_timer1(void)
+static cycle_t bcmring_get_cycles_timer1(struct clocksource *cs)
{
return ~readl(TIMER1_VA_BASE + TIMER_VALUE);
}
-static cycle_t bcmring_get_cycles_timer3(void)
+static cycle_t bcmring_get_cycles_timer3(struct clocksource *cs)
{
return ~readl(TIMER3_VA_BASE + TIMER_VALUE);
}
diff --git a/arch/arm/mach-bcmring/include/mach/system.h b/arch/arm/mach-bcmring/include/mach/system.h
index cdbf93c694a6..38b37060d426 100644
--- a/arch/arm/mach-bcmring/include/mach/system.h
+++ b/arch/arm/mach-bcmring/include/mach/system.h
@@ -29,7 +29,7 @@ static inline void arch_idle(void)
cpu_do_idle();
}
-static inline void arch_reset(char mode, char *cmd)
+static inline void arch_reset(char mode, const char *cmd)
{
printk("arch_reset:%c %x\n", mode, bcmring_arch_warm_reboot);
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..bfac4372be78 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,38 @@ 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
+};
+
+static int da830_evm_mmc_get_ro(int index)
+{
+ int val, status, gpio_num = 33;
+
+ status = gpio_request(gpio_num, "MMC WP\n");
+ if (status < 0) {
+ pr_warning("%s can not open GPIO %d\n", __func__, gpio_num);
+ return 0;
+ }
+ gpio_direction_input(gpio_num);
+ val = gpio_get_value(gpio_num);
+ gpio_free(gpio_num);
+ return val;
+}
+
+static struct davinci_mmc_config da830_evm_mmc_config = {
+ .get_ro = da830_evm_mmc_get_ro,
+ .wires = 4,
+ .version = MMC_CTLR_VERSION_2,
+};
+
static __init void da830_evm_init(void)
{
struct davinci_soc_info *soc_info = &davinci_soc_info;
@@ -94,6 +285,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 +310,37 @@ 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);
+
+ ret = da8xx_pinmux_setup(da830_evm_mmc_sd_pins);
+ if (ret)
+ pr_warning("da830_evm_init: mmc/sd mux setup failed: %d\n",
+ ret);
+
+ ret = da8xx_register_mmcsd0(&da830_evm_mmc_config);
+ if (ret)
+ pr_warning("da830_evm_init: mmc/sd registration failed: %d\n",
+ ret);
+
+#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 +364,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..3d7b5bbeb97d 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,21 +23,18 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
-#include <asm/setup.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>
-
static inline int have_imager(void)
{
/* REVISIT when it's supported, trigger via Kconfig */
@@ -144,6 +140,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 +173,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 = {
@@ -472,6 +474,8 @@ static __init void dm365_evm_init(void)
/* maybe setup mmc1/etc ... _after_ mmc0 */
evm_init_cpld();
+
+ dm365_init_asp(&dm365_evm_snd_data);
}
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..dfdeab5ca8e8 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,70 @@ 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;
+
+ 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 +171,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 +202,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 +223,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 +236,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 +324,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,9 +339,91 @@ 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)
{
struct davinci_clk *c;
@@ -281,12 +432,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 +514,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..a13a6c4716fb 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 <linux/platform_device.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..0fbc2f261ee3 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,7 @@
#include <mach/time.h>
#include <mach/serial.h>
#include <mach/common.h>
+#include <mach/asp.h>
#include "clock.h"
#include "mux.h"
@@ -369,7 +368,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 +455,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),
@@ -603,6 +602,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 +808,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,
@@ -907,6 +934,20 @@ 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(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..2291c0d2c2a0 100644
--- a/arch/arm/mach-davinci/include/mach/dm365.h
+++ b/arch/arm/mach-davinci/include/mach/dm365.h
@@ -16,6 +16,7 @@
#include <linux/platform_device.h>
#include <mach/hardware.h>
#include <mach/emac.h>
+#include <mach/asp.h>
#define DM365_EMAC_BASE (0x01D07000)
#define DM365_EMAC_CNTRL_OFFSET (0x0000)
@@ -25,5 +26,6 @@
#define DM365_EMAC_CNTRL_RAM_SIZE (0x2000)
void __init dm365_init(void);
+void __init dm365_init_asp(struct snd_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..16b8a7fc39bd 100644
--- a/arch/arm/mach-davinci/include/mach/mux.h
+++ b/arch/arm/mach-davinci/include/mach/mux.h
@@ -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..539ed1185a95 100644
--- a/arch/arm/mach-davinci/include/mach/system.h
+++ b/arch/arm/mach-davinci/include/mach/system.h
@@ -11,8 +11,7 @@
#ifndef __ASM_ARCH_SYSTEM_H
#define __ASM_ARCH_SYSTEM_H
-#include <linux/io.h>
-#include <mach/hardware.h>
+#include <asm/proc-fns.h>
extern void davinci_watchdog_reset(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/Kconfig b/arch/arm/mach-ep93xx/Kconfig
index d7291c682a64..9167c3d2a5ed 100644
--- a/arch/arm/mach-ep93xx/Kconfig
+++ b/arch/arm/mach-ep93xx/Kconfig
@@ -17,13 +17,31 @@ config EP93XX_SDCE3_SYNC_PHYS_OFFSET
bool "0x00000000 - SDCE3/SyncBoot"
help
Select this option if you want support for EP93xx boards with the
- first SDRAM bank at 0x00000000
+ first SDRAM bank at 0x00000000.
config EP93XX_SDCE0_PHYS_OFFSET
bool "0xc0000000 - SDCEO"
help
Select this option if you want support for EP93xx boards with the
- first SDRAM bank at 0xc0000000
+ first SDRAM bank at 0xc0000000.
+
+config EP93XX_SDCE1_PHYS_OFFSET
+ bool "0xd0000000 - SDCE1"
+ help
+ Select this option if you want support for EP93xx boards with the
+ first SDRAM bank at 0xd0000000.
+
+config EP93XX_SDCE2_PHYS_OFFSET
+ bool "0xe0000000 - SDCE2"
+ help
+ Select this option if you want support for EP93xx boards with the
+ first SDRAM bank at 0xe0000000.
+
+config EP93XX_SDCE3_ASYNC_PHYS_OFFSET
+ bool "0xf0000000 - SDCE3/AsyncBoot"
+ help
+ Select this option if you want support for EP93xx boards with the
+ first SDRAM bank at 0xf0000000.
endchoice
@@ -112,28 +130,36 @@ config MACH_MICRO9
bool
config MACH_MICRO9H
- bool "Support Contec Hypercontrol Micro9-H"
+ bool "Support Contec Micro9-High"
depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
select MACH_MICRO9
help
Say 'Y' here if you want your kernel to support the
- Contec Hypercontrol Micro9-H board.
+ Contec Micro9-High board.
config MACH_MICRO9M
- bool "Support Contec Hypercontrol Micro9-M"
- depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
+ bool "Support Contec Micro9-Mid"
+ depends on EP93XX_SDCE3_ASYNC_PHYS_OFFSET
select MACH_MICRO9
help
Say 'Y' here if you want your kernel to support the
- Contec Hypercontrol Micro9-M board.
+ Contec Micro9-Mid board.
config MACH_MICRO9L
- bool "Support Contec Hypercontrol Micro9-L"
+ bool "Support Contec Micro9-Lite"
depends on EP93XX_SDCE3_SYNC_PHYS_OFFSET
select MACH_MICRO9
help
Say 'Y' here if you want your kernel to support the
- Contec Hypercontrol Micro9-L board.
+ Contec Micro9-Lite board.
+
+config MACH_MICRO9S
+ bool "Support Contec Micro9-Slim"
+ depends on EP93XX_SDCE3_ASYNC_PHYS_OFFSET
+ select MACH_MICRO9
+ help
+ Say 'Y' here if you want your kernel to support the
+ Contec Micro9-Slim board.
config MACH_TS72XX
bool "Support Technologic Systems TS-72xx SBC"
diff --git a/arch/arm/mach-ep93xx/Makefile.boot b/arch/arm/mach-ep93xx/Makefile.boot
index 27a085a8f12a..0ad33f15c622 100644
--- a/arch/arm/mach-ep93xx/Makefile.boot
+++ b/arch/arm/mach-ep93xx/Makefile.boot
@@ -3,3 +3,12 @@ params_phys-$(CONFIG_EP93XX_SDCE3_SYNC_PHYS_OFFSET) := 0x00000100
zreladdr-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET) := 0xc0008000
params_phys-$(CONFIG_EP93XX_SDCE0_PHYS_OFFSET) := 0xc0000100
+
+ zreladdr-$(CONFIG_EP93XX_SDCE1_PHYS_OFFSET) := 0xd0008000
+params_phys-$(CONFIG_EP93XX_SDCE1_PHYS_OFFSET) := 0xd0000100
+
+ zreladdr-$(CONFIG_EP93XX_SDCE2_PHYS_OFFSET) := 0xe0008000
+params_phys-$(CONFIG_EP93XX_SDCE2_PHYS_OFFSET) := 0xe0000100
+
+ zreladdr-$(CONFIG_EP93XX_SDCE3_ASYNC_PHYS_OFFSET) := 0xf0008000
+params_phys-$(CONFIG_EP93XX_SDCE3_ASYNC_PHYS_OFFSET) := 0xf0000100
diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index dda19cd76194..1d0f9d8aff2e 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -16,13 +16,16 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/io.h>
+#include <linux/spinlock.h>
+
+#include <mach/hardware.h>
#include <asm/clkdev.h>
#include <asm/div64.h>
-#include <mach/hardware.h>
struct clk {
+ struct clk *parent;
unsigned long rate;
int users;
int sw_locked;
@@ -39,40 +42,60 @@ static unsigned long get_uart_rate(struct clk *clk);
static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
static int set_div_rate(struct clk *clk, unsigned long rate);
+
+static struct clk clk_xtali = {
+ .rate = EP93XX_EXT_CLK_RATE,
+};
static struct clk clk_uart1 = {
+ .parent = &clk_xtali,
.sw_locked = 1,
.enable_reg = EP93XX_SYSCON_DEVCFG,
.enable_mask = EP93XX_SYSCON_DEVCFG_U1EN,
.get_rate = get_uart_rate,
};
static struct clk clk_uart2 = {
+ .parent = &clk_xtali,
.sw_locked = 1,
.enable_reg = EP93XX_SYSCON_DEVCFG,
.enable_mask = EP93XX_SYSCON_DEVCFG_U2EN,
.get_rate = get_uart_rate,
};
static struct clk clk_uart3 = {
+ .parent = &clk_xtali,
.sw_locked = 1,
.enable_reg = EP93XX_SYSCON_DEVCFG,
.enable_mask = EP93XX_SYSCON_DEVCFG_U3EN,
.get_rate = get_uart_rate,
};
-static struct clk clk_pll1;
-static struct clk clk_f;
-static struct clk clk_h;
-static struct clk clk_p;
-static struct clk clk_pll2;
+static struct clk clk_pll1 = {
+ .parent = &clk_xtali,
+};
+static struct clk clk_f = {
+ .parent = &clk_pll1,
+};
+static struct clk clk_h = {
+ .parent = &clk_pll1,
+};
+static struct clk clk_p = {
+ .parent = &clk_pll1,
+};
+static struct clk clk_pll2 = {
+ .parent = &clk_xtali,
+};
static struct clk clk_usb_host = {
+ .parent = &clk_pll2,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_USH_EN,
};
static struct clk clk_keypad = {
+ .parent = &clk_xtali,
.sw_locked = 1,
.enable_reg = EP93XX_SYSCON_KEYTCHCLKDIV,
.enable_mask = EP93XX_SYSCON_KEYTCHCLKDIV_KEN,
.set_rate = set_keytchclk_rate,
};
static struct clk clk_pwm = {
+ .parent = &clk_xtali,
.rate = EP93XX_EXT_CLK_RATE,
};
@@ -85,50 +108,62 @@ static struct clk clk_video = {
/* DMA Clocks */
static struct clk clk_m2p0 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P0,
};
static struct clk clk_m2p1 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P1,
};
static struct clk clk_m2p2 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P2,
};
static struct clk clk_m2p3 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P3,
};
static struct clk clk_m2p4 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P4,
};
static struct clk clk_m2p5 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P5,
};
static struct clk clk_m2p6 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P6,
};
static struct clk clk_m2p7 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P7,
};
static struct clk clk_m2p8 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P8,
};
static struct clk clk_m2p9 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2P9,
};
static struct clk clk_m2m0 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M0,
};
static struct clk clk_m2m1 = {
+ .parent = &clk_h,
.enable_reg = EP93XX_SYSCON_PWRCNT,
.enable_mask = EP93XX_SYSCON_PWRCNT_DMA_M2M1,
};
@@ -137,6 +172,7 @@ static struct clk clk_m2m1 = {
{ .dev_id = dev, .con_id = con, .clk = ck }
static struct clk_lookup clocks[] = {
+ INIT_CK(NULL, "xtali", &clk_xtali),
INIT_CK("apb:uart1", NULL, &clk_uart1),
INIT_CK("apb:uart2", NULL, &clk_uart2),
INIT_CK("apb:uart3", NULL, &clk_uart3),
@@ -163,48 +199,84 @@ static struct clk_lookup clocks[] = {
INIT_CK(NULL, "m2m1", &clk_m2m1),
};
+static DEFINE_SPINLOCK(clk_lock);
+
+static void __clk_enable(struct clk *clk)
+{
+ if (!clk->users++) {
+ if (clk->parent)
+ __clk_enable(clk->parent);
+
+ if (clk->enable_reg) {
+ u32 v;
+
+ v = __raw_readl(clk->enable_reg);
+ v |= clk->enable_mask;
+ if (clk->sw_locked)
+ ep93xx_syscon_swlocked_write(v, clk->enable_reg);
+ else
+ __raw_writel(v, clk->enable_reg);
+ }
+ }
+}
int clk_enable(struct clk *clk)
{
- if (!clk->users++ && clk->enable_reg) {
- u32 value;
+ unsigned long flags;
- value = __raw_readl(clk->enable_reg);
- value |= clk->enable_mask;
- if (clk->sw_locked)
- ep93xx_syscon_swlocked_write(value, clk->enable_reg);
- else
- __raw_writel(value, clk->enable_reg);
- }
+ if (!clk)
+ return -EINVAL;
+
+ spin_lock_irqsave(&clk_lock, flags);
+ __clk_enable(clk);
+ spin_unlock_irqrestore(&clk_lock, flags);
return 0;
}
EXPORT_SYMBOL(clk_enable);
-void clk_disable(struct clk *clk)
+static void __clk_disable(struct clk *clk)
{
- if (!--clk->users && clk->enable_reg) {
- u32 value;
+ if (!--clk->users) {
+ if (clk->enable_reg) {
+ u32 v;
+
+ v = __raw_readl(clk->enable_reg);
+ v &= ~clk->enable_mask;
+ if (clk->sw_locked)
+ ep93xx_syscon_swlocked_write(v, clk->enable_reg);
+ else
+ __raw_writel(v, clk->enable_reg);
+ }
- value = __raw_readl(clk->enable_reg);
- value &= ~clk->enable_mask;
- if (clk->sw_locked)
- ep93xx_syscon_swlocked_write(value, clk->enable_reg);
- else
- __raw_writel(value, clk->enable_reg);
+ if (clk->parent)
+ __clk_disable(clk->parent);
}
}
+
+void clk_disable(struct clk *clk)
+{
+ unsigned long flags;
+
+ if (!clk)
+ return;
+
+ spin_lock_irqsave(&clk_lock, flags);
+ __clk_disable(clk);
+ spin_unlock_irqrestore(&clk_lock, flags);
+}
EXPORT_SYMBOL(clk_disable);
static unsigned long get_uart_rate(struct clk *clk)
{
+ unsigned long rate = clk_get_rate(clk->parent);
u32 value;
value = __raw_readl(EP93XX_SYSCON_PWRCNT);
if (value & EP93XX_SYSCON_PWRCNT_UARTBAUD)
- return EP93XX_EXT_CLK_RATE;
+ return rate;
else
- return EP93XX_EXT_CLK_RATE / 2;
+ return rate / 2;
}
unsigned long clk_get_rate(struct clk *clk)
@@ -244,16 +316,16 @@ static int set_keytchclk_rate(struct clk *clk, unsigned long rate)
return 0;
}
-static unsigned long calc_clk_div(unsigned long rate, int *psel, int *esel,
- int *pdiv, int *div)
+static int calc_clk_div(struct clk *clk, unsigned long rate,
+ int *psel, int *esel, int *pdiv, int *div)
{
- unsigned long max_rate, best_rate = 0,
- actual_rate = 0, mclk_rate = 0, rate_err = -1;
+ struct clk *mclk;
+ unsigned long max_rate, actual_rate, mclk_rate, rate_err = -1;
int i, found = 0, __div = 0, __pdiv = 0;
/* Don't exceed the maximum rate */
max_rate = max(max(clk_pll1.rate / 4, clk_pll2.rate / 4),
- (unsigned long)EP93XX_EXT_CLK_RATE / 4);
+ clk_xtali.rate / 4);
rate = min(rate, max_rate);
/*
@@ -267,11 +339,12 @@ static unsigned long calc_clk_div(unsigned long rate, int *psel, int *esel,
*/
for (i = 0; i < 3; i++) {
if (i == 0)
- mclk_rate = EP93XX_EXT_CLK_RATE * 2;
+ mclk = &clk_xtali;
else if (i == 1)
- mclk_rate = clk_pll1.rate * 2;
- else if (i == 2)
- mclk_rate = clk_pll2.rate * 2;
+ mclk = &clk_pll1;
+ else
+ mclk = &clk_pll2;
+ mclk_rate = mclk->rate * 2;
/* Try each predivider value */
for (__pdiv = 4; __pdiv <= 6; __pdiv++) {
@@ -286,7 +359,8 @@ static unsigned long calc_clk_div(unsigned long rate, int *psel, int *esel,
*div = __div;
*psel = (i == 2);
*esel = (i != 0);
- best_rate = actual_rate;
+ clk->parent = mclk;
+ clk->rate = actual_rate;
rate_err = abs(actual_rate - rate);
found = 1;
}
@@ -294,21 +368,19 @@ static unsigned long calc_clk_div(unsigned long rate, int *psel, int *esel,
}
if (!found)
- return 0;
+ return -EINVAL;
- return best_rate;
+ return 0;
}
static int set_div_rate(struct clk *clk, unsigned long rate)
{
- unsigned long actual_rate;
- int psel = 0, esel = 0, pdiv = 0, div = 0;
+ int err, psel = 0, esel = 0, pdiv = 0, div = 0;
u32 val;
- actual_rate = calc_clk_div(rate, &psel, &esel, &pdiv, &div);
- if (actual_rate == 0)
- return -EINVAL;
- clk->rate = actual_rate;
+ err = calc_clk_div(clk, rate, &psel, &esel, &pdiv, &div);
+ if (err)
+ return err;
/* Clear the esel, psel, pdiv and div bits */
val = __raw_readl(clk->enable_reg);
@@ -344,7 +416,7 @@ static unsigned long calc_pll_rate(u32 config_word)
unsigned long long rate;
int i;
- rate = EP93XX_EXT_CLK_RATE;
+ rate = clk_xtali.rate;
rate *= ((config_word >> 11) & 0x1f) + 1; /* X1FBD */
rate *= ((config_word >> 5) & 0x3f) + 1; /* X2FBD */
do_div(rate, (config_word & 0x1f) + 1); /* X2IPD */
@@ -377,7 +449,7 @@ static int __init ep93xx_clock_init(void)
value = __raw_readl(EP93XX_SYSCON_CLOCK_SET1);
if (!(value & 0x00800000)) { /* PLL1 bypassed? */
- clk_pll1.rate = EP93XX_EXT_CLK_RATE;
+ clk_pll1.rate = clk_xtali.rate;
} else {
clk_pll1.rate = calc_pll_rate(value);
}
@@ -388,7 +460,7 @@ static int __init ep93xx_clock_init(void)
value = __raw_readl(EP93XX_SYSCON_CLOCK_SET2);
if (!(value & 0x00080000)) { /* PLL2 bypassed? */
- clk_pll2.rate = EP93XX_EXT_CLK_RATE;
+ clk_pll2.rate = clk_xtali.rate;
} else if (value & 0x00040000) { /* PLL2 enabled? */
clk_pll2.rate = calc_pll_rate(value);
} else {
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index f7ebed942f66..f95dc160c34b 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -550,13 +550,11 @@ void __init ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr)
platform_device_register(&ep93xx_eth_device);
}
-static struct i2c_gpio_platform_data ep93xx_i2c_data = {
- .sda_pin = EP93XX_GPIO_LINE_EEDAT,
- .sda_is_open_drain = 0,
- .scl_pin = EP93XX_GPIO_LINE_EECLK,
- .scl_is_open_drain = 0,
- .udelay = 2,
-};
+
+/*************************************************************************
+ * EP93xx i2c peripheral handling
+ *************************************************************************/
+static struct i2c_gpio_platform_data ep93xx_i2c_data;
static struct platform_device ep93xx_i2c_device = {
.name = "i2c-gpio",
@@ -564,8 +562,25 @@ static struct platform_device ep93xx_i2c_device = {
.dev.platform_data = &ep93xx_i2c_data,
};
-void __init ep93xx_register_i2c(struct i2c_board_info *devices, int num)
+void __init ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
+ struct i2c_board_info *devices, int num)
{
+ /*
+ * Set the EEPROM interface pin drive type control.
+ * Defines the driver type for the EECLK and EEDAT pins as either
+ * open drain, which will require an external pull-up, or a normal
+ * CMOS driver.
+ */
+ if (data->sda_is_open_drain && data->sda_pin != EP93XX_GPIO_LINE_EEDAT)
+ pr_warning("ep93xx: sda != EEDAT, open drain has no effect\n");
+ if (data->scl_is_open_drain && data->scl_pin != EP93XX_GPIO_LINE_EECLK)
+ pr_warning("ep93xx: scl != EECLK, open drain has no effect\n");
+
+ __raw_writel((data->sda_is_open_drain << 1) |
+ (data->scl_is_open_drain << 0),
+ EP93XX_GPIO_EEDRIVE);
+
+ ep93xx_i2c_data = *data;
i2c_register_board_info(0, devices, num);
platform_device_register(&ep93xx_i2c_device);
}
diff --git a/arch/arm/mach-ep93xx/edb93xx.c b/arch/arm/mach-ep93xx/edb93xx.c
index 73145ae5d3fa..a4a7be308000 100644
--- a/arch/arm/mach-ep93xx/edb93xx.c
+++ b/arch/arm/mach-ep93xx/edb93xx.c
@@ -27,8 +27,10 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/i2c.h>
#include <linux/mtd/physmap.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/i2c-gpio.h>
#include <mach/hardware.h>
@@ -76,13 +78,26 @@ static struct ep93xx_eth_data edb93xx_eth_data = {
.phy_id = 1,
};
-static struct i2c_board_info __initdata edb93xxa_i2c_data[] = {
+
+/*************************************************************************
+ * EDB93xx i2c peripheral handling
+ *************************************************************************/
+static struct i2c_gpio_platform_data edb93xx_i2c_gpio_data = {
+ .sda_pin = EP93XX_GPIO_LINE_EEDAT,
+ .sda_is_open_drain = 0,
+ .scl_pin = EP93XX_GPIO_LINE_EECLK,
+ .scl_is_open_drain = 0,
+ .udelay = 0, /* default to 100 kHz */
+ .timeout = 0, /* default to 100 ms */
+};
+
+static struct i2c_board_info __initdata edb93xxa_i2c_board_info[] = {
{
I2C_BOARD_INFO("isl1208", 0x6f),
},
};
-static struct i2c_board_info __initdata edb93xx_i2c_data[] = {
+static struct i2c_board_info __initdata edb93xx_i2c_board_info[] = {
{
I2C_BOARD_INFO("ds1337", 0x68),
},
@@ -92,12 +107,14 @@ static void __init edb93xx_register_i2c(void)
{
if (machine_is_edb9302a() || machine_is_edb9307a() ||
machine_is_edb9315a()) {
- ep93xx_register_i2c(edb93xxa_i2c_data,
- ARRAY_SIZE(edb93xxa_i2c_data));
+ ep93xx_register_i2c(&edb93xx_i2c_gpio_data,
+ edb93xxa_i2c_board_info,
+ ARRAY_SIZE(edb93xxa_i2c_board_info));
} else if (machine_is_edb9307() || machine_is_edb9312() ||
machine_is_edb9315()) {
- ep93xx_register_i2c(edb93xx_i2c_data,
- ARRAY_SIZE(edb93xx_i2c_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/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index 0fbf87b16338..b1f937eda29c 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -52,25 +52,27 @@
#define EP93XX_AHB_VIRT_BASE 0xfef00000
#define EP93XX_AHB_SIZE 0x00100000
+#define EP93XX_AHB_PHYS(x) (EP93XX_AHB_PHYS_BASE + (x))
#define EP93XX_AHB_IOMEM(x) IOMEM(EP93XX_AHB_VIRT_BASE + (x))
#define EP93XX_APB_PHYS_BASE 0x80800000
#define EP93XX_APB_VIRT_BASE 0xfed00000
#define EP93XX_APB_SIZE 0x00200000
+#define EP93XX_APB_PHYS(x) (EP93XX_APB_PHYS_BASE + (x))
#define EP93XX_APB_IOMEM(x) IOMEM(EP93XX_APB_VIRT_BASE + (x))
/* AHB peripherals */
#define EP93XX_DMA_BASE EP93XX_AHB_IOMEM(0x00000000)
-#define EP93XX_ETHERNET_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00010000)
+#define EP93XX_ETHERNET_PHYS_BASE EP93XX_AHB_PHYS(0x00010000)
#define EP93XX_ETHERNET_BASE EP93XX_AHB_IOMEM(0x00010000)
-#define EP93XX_USB_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00020000)
+#define EP93XX_USB_PHYS_BASE EP93XX_AHB_PHYS(0x00020000)
#define EP93XX_USB_BASE EP93XX_AHB_IOMEM(0x00020000)
-#define EP93XX_RASTER_PHYS_BASE (EP93XX_AHB_PHYS_BASE + 0x00030000)
+#define EP93XX_RASTER_PHYS_BASE EP93XX_AHB_PHYS(0x00030000)
#define EP93XX_RASTER_BASE EP93XX_AHB_IOMEM(0x00030000)
#define EP93XX_GRAPHICS_ACCEL_BASE EP93XX_AHB_IOMEM(0x00040000)
@@ -112,21 +114,10 @@
#define EP93XX_GPIO_BASE EP93XX_APB_IOMEM(0x00040000)
#define EP93XX_GPIO_REG(x) (EP93XX_GPIO_BASE + (x))
-#define EP93XX_GPIO_F_INT_TYPE1 EP93XX_GPIO_REG(0x4c)
-#define EP93XX_GPIO_F_INT_TYPE2 EP93XX_GPIO_REG(0x50)
-#define EP93XX_GPIO_F_INT_ACK EP93XX_GPIO_REG(0x54)
-#define EP93XX_GPIO_F_INT_ENABLE EP93XX_GPIO_REG(0x58)
#define EP93XX_GPIO_F_INT_STATUS EP93XX_GPIO_REG(0x5c)
-#define EP93XX_GPIO_A_INT_TYPE1 EP93XX_GPIO_REG(0x90)
-#define EP93XX_GPIO_A_INT_TYPE2 EP93XX_GPIO_REG(0x94)
-#define EP93XX_GPIO_A_INT_ACK EP93XX_GPIO_REG(0x98)
-#define EP93XX_GPIO_A_INT_ENABLE EP93XX_GPIO_REG(0x9c)
#define EP93XX_GPIO_A_INT_STATUS EP93XX_GPIO_REG(0xa0)
-#define EP93XX_GPIO_B_INT_TYPE1 EP93XX_GPIO_REG(0xac)
-#define EP93XX_GPIO_B_INT_TYPE2 EP93XX_GPIO_REG(0xb0)
-#define EP93XX_GPIO_B_INT_ACK EP93XX_GPIO_REG(0xb4)
-#define EP93XX_GPIO_B_INT_ENABLE EP93XX_GPIO_REG(0xb8)
#define EP93XX_GPIO_B_INT_STATUS EP93XX_GPIO_REG(0xbc)
+#define EP93XX_GPIO_EEDRIVE EP93XX_GPIO_REG(0xc8)
#define EP93XX_AAC_BASE EP93XX_APB_IOMEM(0x00080000)
@@ -134,13 +125,13 @@
#define EP93XX_IRDA_BASE EP93XX_APB_IOMEM(0x000b0000)
-#define EP93XX_UART1_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x000c0000)
+#define EP93XX_UART1_PHYS_BASE EP93XX_APB_PHYS(0x000c0000)
#define EP93XX_UART1_BASE EP93XX_APB_IOMEM(0x000c0000)
-#define EP93XX_UART2_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x000d0000)
+#define EP93XX_UART2_PHYS_BASE EP93XX_APB_PHYS(0x000d0000)
#define EP93XX_UART2_BASE EP93XX_APB_IOMEM(0x000d0000)
-#define EP93XX_UART3_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x000e0000)
+#define EP93XX_UART3_PHYS_BASE EP93XX_APB_PHYS(0x000e0000)
#define EP93XX_UART3_BASE EP93XX_APB_IOMEM(0x000e0000)
#define EP93XX_KEY_MATRIX_BASE EP93XX_APB_IOMEM(0x000f0000)
@@ -148,10 +139,10 @@
#define EP93XX_ADC_BASE EP93XX_APB_IOMEM(0x00100000)
#define EP93XX_TOUCHSCREEN_BASE EP93XX_APB_IOMEM(0x00100000)
-#define EP93XX_PWM_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x00110000)
+#define EP93XX_PWM_PHYS_BASE EP93XX_APB_PHYS(0x00110000)
#define EP93XX_PWM_BASE EP93XX_APB_IOMEM(0x00110000)
-#define EP93XX_RTC_PHYS_BASE (EP93XX_APB_PHYS_BASE + 0x00120000)
+#define EP93XX_RTC_PHYS_BASE EP93XX_APB_PHYS(0x00120000)
#define EP93XX_RTC_BASE EP93XX_APB_IOMEM(0x00120000)
#define EP93XX_SYSCON_BASE EP93XX_APB_IOMEM(0x00130000)
@@ -218,6 +209,17 @@
#define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV (1<<16)
#define EP93XX_SYSCON_KEYTCHCLKDIV_KEN (1<<15)
#define EP93XX_SYSCON_KEYTCHCLKDIV_KDIV (1<<0)
+#define EP93XX_SYSCON_SYSCFG EP93XX_SYSCON_REG(0x9c)
+#define EP93XX_SYSCON_SYSCFG_REV_MASK (0xf0000000)
+#define EP93XX_SYSCON_SYSCFG_REV_SHIFT (28)
+#define EP93XX_SYSCON_SYSCFG_SBOOT (1<<8)
+#define EP93XX_SYSCON_SYSCFG_LCSN7 (1<<7)
+#define EP93XX_SYSCON_SYSCFG_LCSN6 (1<<6)
+#define EP93XX_SYSCON_SYSCFG_LASDO (1<<5)
+#define EP93XX_SYSCON_SYSCFG_LEEDA (1<<4)
+#define EP93XX_SYSCON_SYSCFG_LEECLK (1<<3)
+#define EP93XX_SYSCON_SYSCFG_LCSN2 (1<<1)
+#define EP93XX_SYSCON_SYSCFG_LCSN1 (1<<0)
#define EP93XX_SYSCON_SWLOCK EP93XX_SYSCON_REG(0xc0)
#define EP93XX_WATCHDOG_BASE EP93XX_APB_IOMEM(0x00140000)
diff --git a/arch/arm/mach-ep93xx/include/mach/gpio.h b/arch/arm/mach-ep93xx/include/mach/gpio.h
index 0a1498ae899a..c991b149bdf2 100644
--- a/arch/arm/mach-ep93xx/include/mach/gpio.h
+++ b/arch/arm/mach-ep93xx/include/mach/gpio.h
@@ -114,17 +114,9 @@ extern void ep93xx_gpio_int_debounce(unsigned int irq, int enable);
* B0..B7 (7..15) to irq 72..79, and
* F0..F7 (16..24) to irq 80..87.
*/
-static inline int gpio_to_irq(unsigned gpio)
-{
- if (gpio <= EP93XX_GPIO_LINE_MAX_IRQ)
- return 64 + gpio;
-
- return -EINVAL;
-}
-
-static inline int irq_to_gpio(unsigned irq)
-{
- return irq - gpio_to_irq(0);
-}
+#define gpio_to_irq(gpio) \
+ (((gpio) <= EP93XX_GPIO_LINE_MAX_IRQ) ? (64 + (gpio)) : -EINVAL)
+
+#define irq_to_gpio(irq) ((irq) - gpio_to_irq(0))
#endif
diff --git a/arch/arm/mach-ep93xx/include/mach/memory.h b/arch/arm/mach-ep93xx/include/mach/memory.h
index 925b12ea0990..554064e90307 100644
--- a/arch/arm/mach-ep93xx/include/mach/memory.h
+++ b/arch/arm/mach-ep93xx/include/mach/memory.h
@@ -9,6 +9,12 @@
#define PHYS_OFFSET UL(0x00000000)
#elif defined(CONFIG_EP93XX_SDCE0_PHYS_OFFSET)
#define PHYS_OFFSET UL(0xc0000000)
+#elif defined(CONFIG_EP93XX_SDCE1_PHYS_OFFSET)
+#define PHYS_OFFSET UL(0xd0000000)
+#elif defined(CONFIG_EP93XX_SDCE2_PHYS_OFFSET)
+#define PHYS_OFFSET UL(0xe0000000)
+#elif defined(CONFIG_EP93XX_SDCE3_ASYNC_PHYS_OFFSET)
+#define PHYS_OFFSET UL(0xf0000000)
#else
#error "Kconfig bug: No EP93xx PHYS_OFFSET set"
#endif
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index 01a0f0838e5b..a3ec33fd79d4 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -4,6 +4,7 @@
#ifndef __ASSEMBLY__
+struct i2c_gpio_platform_data;
struct i2c_board_info;
struct platform_device;
struct ep93xxfb_mach_info;
@@ -33,7 +34,8 @@ static inline void ep93xx_devcfg_clear_bits(unsigned int bits)
}
void ep93xx_register_eth(struct ep93xx_eth_data *data, int copy_addr);
-void ep93xx_register_i2c(struct i2c_board_info *devices, int num);
+void ep93xx_register_i2c(struct i2c_gpio_platform_data *data,
+ struct i2c_board_info *devices, int num);
void ep93xx_register_fb(struct ep93xxfb_mach_info *data);
void ep93xx_register_pwm(int pwm0, int pwm1);
int ep93xx_pwm_acquire_gpio(struct platform_device *pdev);
diff --git a/arch/arm/mach-ep93xx/micro9.c b/arch/arm/mach-ep93xx/micro9.c
index 0a313e82fb74..d83b80478b09 100644
--- a/arch/arm/mach-ep93xx/micro9.c
+++ b/arch/arm/mach-ep93xx/micro9.c
@@ -2,7 +2,9 @@
* linux/arch/arm/mach-ep93xx/micro9.c
*
* Copyright (C) 2006 Contec Steuerungstechnik & Automation GmbH
- * Manfred Gruber <manfred.gruber@contec.at>
+ * Manfred Gruber <m.gruber@tirol.com>
+ * Copyright (C) 2009 Contec Steuerungstechnik & Automation GmbH
+ * Hubert Feurstein <hubert.feurstein@contec.at>
*
* 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
@@ -20,104 +22,124 @@
#include <asm/mach/arch.h>
-static struct ep93xx_eth_data micro9_eth_data = {
- .phy_id = 0x1f,
-};
-
-static void __init micro9_init(void)
-{
- ep93xx_register_eth(&micro9_eth_data, 1);
-}
-
-/*
- * Micro9-H
- */
-#ifdef CONFIG_MACH_MICRO9H
-static struct physmap_flash_data micro9h_flash_data = {
- .width = 4,
-};
-
-static struct resource micro9h_flash_resource = {
+/*************************************************************************
+ * Micro9 NOR Flash
+ *
+ * Micro9-High has up to 64MB of 32-bit flash on CS1
+ * Micro9-Mid has up to 64MB of either 32-bit or 16-bit flash on CS1
+ * Micro9-Lite uses a seperate MTD map driver for flash support
+ * Micro9-Slim has up to 64MB of either 32-bit or 16-bit flash on CS1
+ *************************************************************************/
+static struct physmap_flash_data micro9_flash_data;
+
+static struct resource micro9_flash_resource = {
.start = EP93XX_CS1_PHYS_BASE,
.end = EP93XX_CS1_PHYS_BASE + SZ_64M - 1,
.flags = IORESOURCE_MEM,
};
-static struct platform_device micro9h_flash = {
+static struct platform_device micro9_flash = {
.name = "physmap-flash",
.id = 0,
.dev = {
- .platform_data = &micro9h_flash_data,
+ .platform_data = &micro9_flash_data,
},
.num_resources = 1,
- .resource = &micro9h_flash_resource,
+ .resource = &micro9_flash_resource,
};
-static void __init micro9h_init(void)
+static void __init __micro9_register_flash(unsigned int width)
+{
+ micro9_flash_data.width = width;
+
+ platform_device_register(&micro9_flash);
+}
+
+static unsigned int __init micro9_detect_bootwidth(void)
+{
+ u32 v;
+
+ /* Detect the bus width of the external flash memory */
+ v = __raw_readl(EP93XX_SYSCON_SYSCFG);
+ if (v & EP93XX_SYSCON_SYSCFG_LCSN7)
+ return 4; /* 32-bit */
+ else
+ return 2; /* 16-bit */
+}
+
+static void __init micro9_register_flash(void)
{
- platform_device_register(&micro9h_flash);
+ if (machine_is_micro9())
+ __micro9_register_flash(4);
+ else if (machine_is_micro9m() || machine_is_micro9s())
+ __micro9_register_flash(micro9_detect_bootwidth());
}
-static void __init micro9h_init_machine(void)
+
+/*************************************************************************
+ * Micro9 Ethernet
+ *************************************************************************/
+static struct ep93xx_eth_data micro9_eth_data = {
+ .phy_id = 0x1f,
+};
+
+
+static void __init micro9_init_machine(void)
{
ep93xx_init_devices();
- micro9_init();
- micro9h_init();
+ ep93xx_register_eth(&micro9_eth_data, 1);
+ micro9_register_flash();
}
-MACHINE_START(MICRO9, "Contec Hypercontrol Micro9-H")
- /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */
+
+#ifdef CONFIG_MACH_MICRO9H
+MACHINE_START(MICRO9, "Contec Micro9-High")
+ /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
.phys_io = EP93XX_APB_PHYS_BASE,
.io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
.boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
.timer = &ep93xx_timer,
- .init_machine = micro9h_init_machine,
+ .init_machine = micro9_init_machine,
MACHINE_END
#endif
-/*
- * Micro9-M
- */
#ifdef CONFIG_MACH_MICRO9M
-static void __init micro9m_init_machine(void)
-{
- ep93xx_init_devices();
- micro9_init();
-}
-
-MACHINE_START(MICRO9M, "Contec Hypercontrol Micro9-M")
- /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */
+MACHINE_START(MICRO9M, "Contec Micro9-Mid")
+ /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
.phys_io = EP93XX_APB_PHYS_BASE,
.io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
- .boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
+ .boot_params = EP93XX_SDCE3_PHYS_BASE_ASYNC + 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
.timer = &ep93xx_timer,
- .init_machine = micro9m_init_machine,
+ .init_machine = micro9_init_machine,
MACHINE_END
#endif
-/*
- * Micro9-L
- */
#ifdef CONFIG_MACH_MICRO9L
-static void __init micro9l_init_machine(void)
-{
- ep93xx_init_devices();
- micro9_init();
-}
-
-MACHINE_START(MICRO9L, "Contec Hypercontrol Micro9-L")
- /* Maintainer: Manfred Gruber <manfred.gruber@contec.at> */
+MACHINE_START(MICRO9L, "Contec Micro9-Lite")
+ /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
.phys_io = EP93XX_APB_PHYS_BASE,
.io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
.boot_params = EP93XX_SDCE3_PHYS_BASE_SYNC + 0x100,
.map_io = ep93xx_map_io,
.init_irq = ep93xx_init_irq,
.timer = &ep93xx_timer,
- .init_machine = micro9l_init_machine,
+ .init_machine = micro9_init_machine,
MACHINE_END
#endif
+#ifdef CONFIG_MACH_MICRO9S
+MACHINE_START(MICRO9S, "Contec Micro9-Slim")
+ /* Maintainer: Hubert Feurstein <hubert.feurstein@contec.at> */
+ .phys_io = EP93XX_APB_PHYS_BASE,
+ .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+ .boot_params = EP93XX_SDCE3_PHYS_BASE_ASYNC + 0x100,
+ .map_io = ep93xx_map_io,
+ .init_irq = ep93xx_init_irq,
+ .timer = &ep93xx_timer,
+ .init_machine = micro9_init_machine,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index 901cc205015e..148d25fc636f 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -31,6 +31,7 @@
#include <mach/hardware.h>
#include <asm/irq.h>
+#include <asm/signal.h>
#include <asm/system.h>
#include <asm/mach/pci.h>
#include <asm/irq_regs.h>
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-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index b45ad312c587..2b0eb1ba5d7f 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -38,49 +38,49 @@
static int board_keymap[] = {
KEY(0, 0, KEY_Q),
- KEY(0, 1, KEY_W),
- KEY(0, 2, KEY_E),
- KEY(0, 3, KEY_R),
- KEY(0, 4, KEY_T),
- KEY(0, 5, KEY_Y),
- KEY(0, 6, KEY_U),
- KEY(0, 7, KEY_I),
- KEY(1, 0, KEY_O),
+ KEY(0, 1, KEY_O),
+ KEY(0, 2, KEY_P),
+ KEY(0, 3, KEY_COMMA),
+ KEY(0, 4, KEY_BACKSPACE),
+ KEY(0, 6, KEY_A),
+ KEY(0, 7, KEY_S),
+ KEY(1, 0, KEY_W),
KEY(1, 1, KEY_D),
- KEY(1, 2, KEY_DOT),
- KEY(1, 3, KEY_V),
- KEY(1, 4, KEY_DOWN),
- KEY(2, 0, KEY_P),
- KEY(2, 1, KEY_F),
+ KEY(1, 2, KEY_F),
+ KEY(1, 3, KEY_G),
+ KEY(1, 4, KEY_H),
+ KEY(1, 5, KEY_J),
+ KEY(1, 6, KEY_K),
+ KEY(1, 7, KEY_L),
+ KEY(2, 0, KEY_E),
+ KEY(2, 1, KEY_DOT),
KEY(2, 2, KEY_UP),
- KEY(2, 3, KEY_B),
- KEY(2, 4, KEY_RIGHT),
- KEY(3, 0, KEY_COMMA),
- KEY(3, 1, KEY_G),
- KEY(3, 2, KEY_ENTER),
+ KEY(2, 3, KEY_ENTER),
+ KEY(2, 5, KEY_Z),
+ KEY(2, 6, KEY_X),
+ KEY(2, 7, KEY_C),
+ KEY(3, 0, KEY_R),
+ KEY(3, 1, KEY_V),
+ KEY(3, 2, KEY_B),
KEY(3, 3, KEY_N),
- KEY(4, 0, KEY_BACKSPACE),
- KEY(4, 1, KEY_H),
- KEY(4, 3, KEY_M),
+ KEY(3, 4, KEY_M),
+ KEY(3, 5, KEY_SPACE),
+ KEY(3, 6, KEY_SPACE),
+ KEY(3, 7, KEY_LEFT),
+ KEY(4, 0, KEY_T),
+ KEY(4, 1, KEY_DOWN),
+ KEY(4, 2, KEY_RIGHT),
KEY(4, 4, KEY_LEFTCTRL),
- KEY(5, 1, KEY_J),
- KEY(5, 2, KEY_Z),
- KEY(5, 3, KEY_SPACE),
- KEY(5, 4, KEY_LEFTSHIFT),
- KEY(6, 0, KEY_A),
- KEY(6, 1, KEY_K),
- KEY(6, 2, KEY_X),
- KEY(6, 3, KEY_SPACE),
- KEY(6, 4, KEY_FN),
- KEY(7, 0, KEY_S),
- KEY(7, 1, KEY_L),
- KEY(7, 2, KEY_C),
- KEY(7, 3, KEY_LEFT),
- KEY(0xff, 0, KEY_F6),
- KEY(0xff, 1, KEY_F7),
- KEY(0xff, 2, KEY_F8),
- KEY(0xff, 4, KEY_F9),
- KEY(0xff, 5, KEY_F10),
+ KEY(4, 5, KEY_RIGHTALT),
+ KEY(4, 6, KEY_LEFTSHIFT),
+ KEY(5, 0, KEY_Y),
+ KEY(6, 0, KEY_U),
+ KEY(7, 0, KEY_I),
+ KEY(7, 1, KEY_F7),
+ KEY(7, 2, KEY_F8),
+ KEY(0xff, 2, KEY_F9),
+ KEY(0xff, 4, KEY_F10),
+ KEY(0xff, 5, KEY_F11),
};
static struct matrix_keymap_data board_map_data = {
@@ -444,7 +444,7 @@ static int __init rx51_i2c_init(void)
rx51_twldata.vaux3 = &rx51_vaux3_cam;
rx51_twldata.vmmc2 = &rx51_vmmc2;
}
- omap_register_i2c_bus(1, 2600, rx51_peripherals_i2c_board_info_1,
+ omap_register_i2c_bus(1, 2200, rx51_peripherals_i2c_board_info_1,
ARRAY_SIZE(rx51_peripherals_i2c_board_info_1));
omap_register_i2c_bus(2, 100, NULL, 0);
omap_register_i2c_bus(3, 400, NULL, 0);
diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c
index b7b32208ced7..fd3369d5e5cb 100644
--- a/arch/arm/mach-omap2/board-zoom2.c
+++ b/arch/arm/mach-omap2/board-zoom2.c
@@ -25,6 +25,7 @@
#include <mach/keypad.h>
#include "mmc-twl4030.h"
+#include "sdram-micron-mt46h32m32lf-6.h"
/* Zoom2 has Qwerty keyboard*/
static int board_keymap[] = {
@@ -213,7 +214,8 @@ static void __init omap_zoom2_init_irq(void)
{
omap_board_config = zoom2_config;
omap_board_config_size = ARRAY_SIZE(zoom2_config);
- omap2_init_common_hw(NULL, NULL);
+ omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
+ mt46h32m32lf6_sdrc_params);
omap_init_irq();
omap_gpio_init();
}
diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c
index bc5d3ac66611..e2dbedd581e8 100644
--- a/arch/arm/mach-omap2/clock24xx.c
+++ b/arch/arm/mach-omap2/clock24xx.c
@@ -769,6 +769,7 @@ int __init omap2_clk_init(void)
if (c->cpu & cpu_mask) {
clkdev_add(&c->lk);
clk_register(c->lk.clk);
+ omap2_init_clk_clkdm(c->lk.clk);
}
/* Check the MPU rate set by bootloader */
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index fafcd32e6907..489556eecbd1 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -338,6 +338,13 @@ static struct omap_clk omap34xx_clks[] = {
*/
#define SDRC_MPURATE_LOOPS 96
+/*
+ * DPLL5_FREQ_FOR_USBHOST: USBHOST and USBTLL are the only clocks
+ * that are sourced by DPLL5, and both of these require this clock
+ * to be at 120 MHz for proper operation.
+ */
+#define DPLL5_FREQ_FOR_USBHOST 120000000
+
/**
* omap3430es2_clk_ssi_find_idlest - return CM_IDLEST info for SSI
* @clk: struct clk * being enabled
@@ -1056,6 +1063,28 @@ void omap2_clk_prepare_for_reboot(void)
#endif
}
+static void omap3_clk_lock_dpll5(void)
+{
+ struct clk *dpll5_clk;
+ struct clk *dpll5_m2_clk;
+
+ dpll5_clk = clk_get(NULL, "dpll5_ck");
+ clk_set_rate(dpll5_clk, DPLL5_FREQ_FOR_USBHOST);
+ clk_enable(dpll5_clk);
+
+ /* Enable autoidle to allow it to enter low power bypass */
+ omap3_dpll_allow_idle(dpll5_clk);
+
+ /* Program dpll5_m2_clk divider for no division */
+ dpll5_m2_clk = clk_get(NULL, "dpll5_m2_ck");
+ clk_enable(dpll5_m2_clk);
+ clk_set_rate(dpll5_m2_clk, DPLL5_FREQ_FOR_USBHOST);
+
+ clk_disable(dpll5_m2_clk);
+ clk_disable(dpll5_clk);
+ return;
+}
+
/* REVISIT: Move this init stuff out into clock.c */
/*
@@ -1148,6 +1177,12 @@ int __init omap2_clk_init(void)
*/
clk_enable_init_clocks();
+ /*
+ * Lock DPLL5 and put it in autoidle.
+ */
+ if (omap_rev() >= OMAP3430_REV_ES2_0)
+ omap3_clk_lock_dpll5();
+
/* Avoid sleeping during omap2_clk_prepare_for_reboot() */
/* REVISIT: not yet ready for 343x */
#if 0
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 4ef7b4f5474e..58aff8485df9 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -137,6 +137,36 @@ static void _clkdm_del_autodeps(struct clockdomain *clkdm)
}
}
+/*
+ * _omap2_clkdm_set_hwsup - set the hwsup idle transition bit
+ * @clkdm: struct clockdomain *
+ * @enable: int 0 to disable, 1 to enable
+ *
+ * Internal helper for actually switching the bit that controls hwsup
+ * idle transitions for clkdm.
+ */
+static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable)
+{
+ u32 v;
+
+ if (cpu_is_omap24xx()) {
+ if (enable)
+ v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
+ else
+ v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
+ } else if (cpu_is_omap34xx()) {
+ if (enable)
+ v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
+ else
+ v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
+ } else {
+ BUG();
+ }
+
+ cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
+ v << __ffs(clkdm->clktrctrl_mask),
+ clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
+}
static struct clockdomain *_clkdm_lookup(const char *name)
{
@@ -456,8 +486,6 @@ int omap2_clkdm_wakeup(struct clockdomain *clkdm)
*/
void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
{
- u32 v;
-
if (!clkdm)
return;
@@ -473,18 +501,7 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
if (atomic_read(&clkdm->usecount) > 0)
_clkdm_add_autodeps(clkdm);
- if (cpu_is_omap24xx())
- v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
- else if (cpu_is_omap34xx())
- v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
- else
- BUG();
-
-
- cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
- v << __ffs(clkdm->clktrctrl_mask),
- clkdm->pwrdm.ptr->prcm_offs,
- CM_CLKSTCTRL);
+ _omap2_clkdm_set_hwsup(clkdm, 1);
pwrdm_clkdm_state_switch(clkdm);
}
@@ -500,8 +517,6 @@ void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
*/
void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
{
- u32 v;
-
if (!clkdm)
return;
@@ -514,16 +529,7 @@ void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
clkdm->name);
- if (cpu_is_omap24xx())
- v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
- else if (cpu_is_omap34xx())
- v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
- else
- BUG();
-
- cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
- v << __ffs(clkdm->clktrctrl_mask),
- clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
+ _omap2_clkdm_set_hwsup(clkdm, 0);
if (atomic_read(&clkdm->usecount) > 0)
_clkdm_del_autodeps(clkdm);
@@ -569,10 +575,14 @@ int omap2_clkdm_clk_enable(struct clockdomain *clkdm, struct clk *clk)
v = omap2_clkdm_clktrctrl_read(clkdm);
if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
- (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+ (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) {
+ /* Disable HW transitions when we are changing deps */
+ _omap2_clkdm_set_hwsup(clkdm, 0);
_clkdm_add_autodeps(clkdm);
- else
+ _omap2_clkdm_set_hwsup(clkdm, 1);
+ } else {
omap2_clkdm_wakeup(clkdm);
+ }
pwrdm_wait_transition(clkdm->pwrdm.ptr);
pwrdm_clkdm_state_switch(clkdm);
@@ -623,10 +633,14 @@ int omap2_clkdm_clk_disable(struct clockdomain *clkdm, struct clk *clk)
v = omap2_clkdm_clktrctrl_read(clkdm);
if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
- (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+ (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) {
+ /* Disable HW transitions when we are changing deps */
+ _omap2_clkdm_set_hwsup(clkdm, 0);
_clkdm_del_autodeps(clkdm);
- else
+ _omap2_clkdm_set_hwsup(clkdm, 1);
+ } else {
omap2_clkdm_sleep(clkdm);
+ }
pwrdm_clkdm_state_switch(clkdm);
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 1b4c1600f8d8..2fc4d6abbd0a 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -541,7 +541,7 @@ static int __init pm_dbg_init(void)
printk(KERN_ERR "%s: only OMAP3 supported\n", __func__);
return -ENODEV;
}
-
+
d = debugfs_create_dir("pm_debug", NULL);
if (IS_ERR(d))
return PTR_ERR(d);
@@ -551,7 +551,7 @@ static int __init pm_dbg_init(void)
(void) debugfs_create_file("time", S_IRUGO,
d, (void *)DEBUG_FILE_TIMERS, &debug_fops);
- pwrdm_for_each(pwrdms_setup, (void *)d);
+ pwrdm_for_each_nolock(pwrdms_setup, (void *)d);
pm_dbg_dir = debugfs_create_dir("registers", d);
if (IS_ERR(pm_dbg_dir))
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 0ff5a6c53aa0..378c2f618358 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -51,97 +51,112 @@ static void (*_omap_sram_idle)(u32 *addr, int save_state);
static struct powerdomain *mpu_pwrdm;
-/* PRCM Interrupt Handler for wakeups */
-static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+/*
+ * PRCM Interrupt Handler Helper Function
+ *
+ * The purpose of this function is to clear any wake-up events latched
+ * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
+ * may occur whilst attempting to clear a PM_WKST_x register and thus
+ * set another bit in this register. A while loop is used to ensure
+ * that any peripheral wake-up events occurring while attempting to
+ * clear the PM_WKST_x are detected and cleared.
+ */
+static int prcm_clear_mod_irqs(s16 module, u8 regs)
{
- u32 wkst, irqstatus_mpu;
- u32 fclk, iclk;
-
- /* WKUP */
- wkst = prm_read_mod_reg(WKUP_MOD, PM_WKST);
+ u32 wkst, fclk, iclk, clken;
+ u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
+ u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
+ u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
+ u16 grpsel_off = (regs == 3) ?
+ OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
+ int c = 0;
+
+ wkst = prm_read_mod_reg(module, wkst_off);
+ wkst &= prm_read_mod_reg(module, grpsel_off);
if (wkst) {
- iclk = cm_read_mod_reg(WKUP_MOD, CM_ICLKEN);
- fclk = cm_read_mod_reg(WKUP_MOD, CM_FCLKEN);
- cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_ICLKEN);
- cm_set_mod_reg_bits(wkst, WKUP_MOD, CM_FCLKEN);
- prm_write_mod_reg(wkst, WKUP_MOD, PM_WKST);
- while (prm_read_mod_reg(WKUP_MOD, PM_WKST))
- cpu_relax();
- cm_write_mod_reg(iclk, WKUP_MOD, CM_ICLKEN);
- cm_write_mod_reg(fclk, WKUP_MOD, CM_FCLKEN);
+ iclk = cm_read_mod_reg(module, iclk_off);
+ fclk = cm_read_mod_reg(module, fclk_off);
+ while (wkst) {
+ clken = wkst;
+ cm_set_mod_reg_bits(clken, module, iclk_off);
+ /*
+ * For USBHOST, we don't know whether HOST1 or
+ * HOST2 woke us up, so enable both f-clocks
+ */
+ if (module == OMAP3430ES2_USBHOST_MOD)
+ clken |= 1 << OMAP3430ES2_EN_USBHOST2_SHIFT;
+ cm_set_mod_reg_bits(clken, module, fclk_off);
+ prm_write_mod_reg(wkst, module, wkst_off);
+ wkst = prm_read_mod_reg(module, wkst_off);
+ c++;
+ }
+ cm_write_mod_reg(iclk, module, iclk_off);
+ cm_write_mod_reg(fclk, module, fclk_off);
}
- /* CORE */
- wkst = prm_read_mod_reg(CORE_MOD, PM_WKST1);
- if (wkst) {
- iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN1);
- fclk = cm_read_mod_reg(CORE_MOD, CM_FCLKEN1);
- cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN1);
- cm_set_mod_reg_bits(wkst, CORE_MOD, CM_FCLKEN1);
- prm_write_mod_reg(wkst, CORE_MOD, PM_WKST1);
- while (prm_read_mod_reg(CORE_MOD, PM_WKST1))
- cpu_relax();
- cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN1);
- cm_write_mod_reg(fclk, CORE_MOD, CM_FCLKEN1);
- }
- wkst = prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3);
- if (wkst) {
- iclk = cm_read_mod_reg(CORE_MOD, CM_ICLKEN3);
- fclk = cm_read_mod_reg(CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
- cm_set_mod_reg_bits(wkst, CORE_MOD, CM_ICLKEN3);
- cm_set_mod_reg_bits(wkst, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
- prm_write_mod_reg(wkst, CORE_MOD, OMAP3430ES2_PM_WKST3);
- while (prm_read_mod_reg(CORE_MOD, OMAP3430ES2_PM_WKST3))
- cpu_relax();
- cm_write_mod_reg(iclk, CORE_MOD, CM_ICLKEN3);
- cm_write_mod_reg(fclk, CORE_MOD, OMAP3430ES2_CM_FCLKEN3);
- }
+ return c;
+}
- /* PER */
- wkst = prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST);
- if (wkst) {
- iclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_ICLKEN);
- fclk = cm_read_mod_reg(OMAP3430_PER_MOD, CM_FCLKEN);
- cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_ICLKEN);
- cm_set_mod_reg_bits(wkst, OMAP3430_PER_MOD, CM_FCLKEN);
- prm_write_mod_reg(wkst, OMAP3430_PER_MOD, PM_WKST);
- while (prm_read_mod_reg(OMAP3430_PER_MOD, PM_WKST))
- cpu_relax();
- cm_write_mod_reg(iclk, OMAP3430_PER_MOD, CM_ICLKEN);
- cm_write_mod_reg(fclk, OMAP3430_PER_MOD, CM_FCLKEN);
- }
+static int _prcm_int_handle_wakeup(void)
+{
+ int c;
+ c = prcm_clear_mod_irqs(WKUP_MOD, 1);
+ c += prcm_clear_mod_irqs(CORE_MOD, 1);
+ c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
if (omap_rev() > OMAP3430_REV_ES1_0) {
- /* USBHOST */
- wkst = prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD, PM_WKST);
- if (wkst) {
- iclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
- CM_ICLKEN);
- fclk = cm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
- CM_FCLKEN);
- cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
- CM_ICLKEN);
- cm_set_mod_reg_bits(wkst, OMAP3430ES2_USBHOST_MOD,
- CM_FCLKEN);
- prm_write_mod_reg(wkst, OMAP3430ES2_USBHOST_MOD,
- PM_WKST);
- while (prm_read_mod_reg(OMAP3430ES2_USBHOST_MOD,
- PM_WKST))
- cpu_relax();
- cm_write_mod_reg(iclk, OMAP3430ES2_USBHOST_MOD,
- CM_ICLKEN);
- cm_write_mod_reg(fclk, OMAP3430ES2_USBHOST_MOD,
- CM_FCLKEN);
- }
+ c += prcm_clear_mod_irqs(CORE_MOD, 3);
+ c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
}
- irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
- OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
- prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
- OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+ return c;
+}
+
+/*
+ * PRCM Interrupt Handler
+ *
+ * The PRM_IRQSTATUS_MPU register indicates if there are any pending
+ * interrupts from the PRCM for the MPU. These bits must be cleared in
+ * order to clear the PRCM interrupt. The PRCM interrupt handler is
+ * implemented to simply clear the PRM_IRQSTATUS_MPU in order to clear
+ * the PRCM interrupt. Please note that bit 0 of the PRM_IRQSTATUS_MPU
+ * register indicates that a wake-up event is pending for the MPU and
+ * this bit can only be cleared if the all the wake-up events latched
+ * in the various PM_WKST_x registers have been cleared. The interrupt
+ * handler is implemented using a do-while loop so that if a wake-up
+ * event occurred during the processing of the prcm interrupt handler
+ * (setting a bit in the corresponding PM_WKST_x register and thus
+ * preventing us from clearing bit 0 of the PRM_IRQSTATUS_MPU register)
+ * this would be handled.
+ */
+static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
+{
+ u32 irqstatus_mpu;
+ int c = 0;
+
+ do {
+ irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
+ OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+
+ if (irqstatus_mpu & (OMAP3430_WKUP_ST | OMAP3430_IO_ST)) {
+ c = _prcm_int_handle_wakeup();
+
+ /*
+ * Is the MPU PRCM interrupt handler racing with the
+ * IVA2 PRCM interrupt handler ?
+ */
+ WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup "
+ "but no wakeup sources are marked\n");
+ } else {
+ /* XXX we need to expand our PRCM interrupt handler */
+ WARN(1, "prcm: WARNING: PRCM interrupt received, but "
+ "no code to handle it (%08x)\n", irqstatus_mpu);
+ }
+
+ prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
+ OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
- while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET))
- cpu_relax();
+ } while (prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET));
return IRQ_HANDLED;
}
@@ -624,6 +639,16 @@ static void __init prcm_setup_regs(void)
prm_write_mod_reg(OMAP3430_IO_EN | OMAP3430_WKUP_EN,
OCP_MOD, OMAP3_PRM_IRQENABLE_MPU_OFFSET);
+ /* Enable GPIO wakeups in PER */
+ prm_write_mod_reg(OMAP3430_EN_GPIO2 | OMAP3430_EN_GPIO3 |
+ OMAP3430_EN_GPIO4 | OMAP3430_EN_GPIO5 |
+ OMAP3430_EN_GPIO6, OMAP3430_PER_MOD, PM_WKEN);
+ /* and allow them to wake up MPU */
+ prm_write_mod_reg(OMAP3430_GRPSEL_GPIO2 | OMAP3430_EN_GPIO3 |
+ OMAP3430_GRPSEL_GPIO4 | OMAP3430_EN_GPIO5 |
+ OMAP3430_GRPSEL_GPIO6,
+ OMAP3430_PER_MOD, OMAP3430_PM_MPUGRPSEL);
+
/* Don't attach IVA interrupts */
prm_write_mod_reg(0, WKUP_MOD, OMAP3430_PM_IVAGRPSEL);
prm_write_mod_reg(0, CORE_MOD, OMAP3430_PM_IVAGRPSEL1);
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 2594cbff3947..f00289abd30f 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -273,35 +273,50 @@ struct powerdomain *pwrdm_lookup(const char *name)
}
/**
- * pwrdm_for_each - call function on each registered clockdomain
+ * pwrdm_for_each_nolock - call function on each registered clockdomain
* @fn: callback function *
*
* Call the supplied function for each registered powerdomain. The
* callback function can return anything but 0 to bail out early from
- * the iterator. The callback function is called with the pwrdm_rwlock
- * held for reading, so no powerdomain structure manipulation
- * functions should be called from the callback, although hardware
- * powerdomain control functions are fine. Returns the last return
- * value of the callback function, which should be 0 for success or
- * anything else to indicate failure; or -EINVAL if the function
- * pointer is null.
+ * the iterator. Returns the last return value of the callback function, which
+ * should be 0 for success or anything else to indicate failure; or -EINVAL if
+ * the function pointer is null.
*/
-int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
- void *user)
+int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
+ void *user)
{
struct powerdomain *temp_pwrdm;
- unsigned long flags;
int ret = 0;
if (!fn)
return -EINVAL;
- read_lock_irqsave(&pwrdm_rwlock, flags);
list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
ret = (*fn)(temp_pwrdm, user);
if (ret)
break;
}
+
+ return ret;
+}
+
+/**
+ * pwrdm_for_each - call function on each registered clockdomain
+ * @fn: callback function *
+ *
+ * This function is the same as 'pwrdm_for_each_nolock()', but keeps the
+ * &pwrdm_rwlock locked for reading, so no powerdomain structure manipulation
+ * functions should be called from the callback, although hardware powerdomain
+ * control functions are fine.
+ */
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
+ void *user)
+{
+ unsigned long flags;
+ int ret;
+
+ read_lock_irqsave(&pwrdm_rwlock, flags);
+ ret = pwrdm_for_each_nolock(fn, user);
read_unlock_irqrestore(&pwrdm_rwlock, flags);
return ret;
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..ef66df82e57f 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>
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/cpufreq-pxa2xx.c b/arch/arm/mach-pxa/cpufreq-pxa2xx.c
index 3a8ee2272add..983cc8c20081 100644
--- a/arch/arm/mach-pxa/cpufreq-pxa2xx.c
+++ b/arch/arm/mach-pxa/cpufreq-pxa2xx.c
@@ -155,7 +155,7 @@ MODULE_PARM_DESC(pxa255_turbo_table, "Selects the frequency table (0 = run table
static pxa_freqs_t pxa27x_freqs[] = {
{104000, 104000, PXA27x_CCCR(1, 8, 2), 0, CCLKCFG2(1, 0, 1), 900000, 1705000 },
- {156000, 104000, PXA27x_CCCR(1, 8, 6), 0, CCLKCFG2(1, 1, 1), 1000000, 1705000 },
+ {156000, 104000, PXA27x_CCCR(1, 8, 3), 0, CCLKCFG2(1, 0, 1), 1000000, 1705000 },
{208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1), 1180000, 1705000 },
{312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1), 1250000, 1705000 },
{416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1), 1350000, 1705000 },
diff --git a/arch/arm/mach-pxa/csb726.c b/arch/arm/mach-pxa/csb726.c
index 79141f862728..965480eb4fe6 100644
--- a/arch/arm/mach-pxa/csb726.c
+++ b/arch/arm/mach-pxa/csb726.c
@@ -238,7 +238,7 @@ static struct resource csb726_lan_resources[] = {
};
struct smsc911x_platform_config csb726_lan_config = {
- .irq_type = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+ .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
.irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
.flags = SMSC911X_USE_32BIT,
.phy_interface = PHY_INTERFACE_MODE_MII,
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/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-sa1100/Makefile b/arch/arm/mach-sa1100/Makefile
index 8a5546e6d547..bb7b8198d0c4 100644
--- a/arch/arm/mach-sa1100/Makefile
+++ b/arch/arm/mach-sa1100/Makefile
@@ -25,6 +25,7 @@ led-$(CONFIG_SA1100_CERF) += leds-cerf.o
obj-$(CONFIG_SA1100_COLLIE) += collie.o
+obj-$(CONFIG_SA1100_H3100) += h3600.o
obj-$(CONFIG_SA1100_H3600) += h3600.o
obj-$(CONFIG_SA1100_HACKKIT) += hackkit.o
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
index 8f5c13f4c936..295e25dd6381 100644
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -12,6 +12,7 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/assembler.h>
+#include <asm/unwind.h>
#include "proc-macros.S"
@@ -121,11 +122,13 @@ ENTRY(v6_coherent_kern_range)
* - the Icache does not read data from the write buffer
*/
ENTRY(v6_coherent_user_range)
-
+ UNWIND(.fnstart )
#ifdef HARVARD_CACHE
bic r0, r0, #CACHE_LINE_SIZE - 1
-1: mcr p15, 0, r0, c7, c10, 1 @ clean D line
+1:
+ USER( mcr p15, 0, r0, c7, c10, 1 ) @ clean D line
add r0, r0, #CACHE_LINE_SIZE
+2:
cmp r0, r1
blo 1b
#endif
@@ -143,6 +146,19 @@ ENTRY(v6_coherent_user_range)
mov pc, lr
/*
+ * Fault handling for the cache operation above. If the virtual address in r0
+ * isn't mapped, just try the next page.
+ */
+9001:
+ mov r0, r0, lsr #12
+ mov r0, r0, lsl #12
+ add r0, r0, #4096
+ b 2b
+ UNWIND(.fnend )
+ENDPROC(v6_coherent_user_range)
+ENDPROC(v6_coherent_kern_range)
+
+/*
* v6_flush_kern_dcache_page(kaddr)
*
* Ensure that the data held in the page kaddr is written back
diff --git a/arch/arm/mm/cache-v7.S b/arch/arm/mm/cache-v7.S
index bda0ec31a4e2..e1bd9759617f 100644
--- a/arch/arm/mm/cache-v7.S
+++ b/arch/arm/mm/cache-v7.S
@@ -13,6 +13,7 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/assembler.h>
+#include <asm/unwind.h>
#include "proc-macros.S"
@@ -153,13 +154,16 @@ ENTRY(v7_coherent_kern_range)
* - the Icache does not read data from the write buffer
*/
ENTRY(v7_coherent_user_range)
+ UNWIND(.fnstart )
dcache_line_size r2, r3
sub r3, r2, #1
bic r0, r0, r3
-1: mcr p15, 0, r0, c7, c11, 1 @ clean D line to the point of unification
+1:
+ USER( mcr p15, 0, r0, c7, c11, 1 ) @ clean D line to the point of unification
dsb
- mcr p15, 0, r0, c7, c5, 1 @ invalidate I line
+ USER( mcr p15, 0, r0, c7, c5, 1 ) @ invalidate I line
add r0, r0, r2
+2:
cmp r0, r1
blo 1b
mov r0, #0
@@ -167,6 +171,17 @@ ENTRY(v7_coherent_user_range)
dsb
isb
mov pc, lr
+
+/*
+ * Fault handling for the cache operation above. If the virtual address in r0
+ * isn't mapped, just try the next page.
+ */
+9001:
+ mov r0, r0, lsr #12
+ mov r0, r0, lsl #12
+ add r0, r0, #4096
+ b 2b
+ UNWIND(.fnend )
ENDPROC(v7_coherent_kern_range)
ENDPROC(v7_coherent_user_range)
diff --git a/arch/arm/mm/fault-armv.c b/arch/arm/mm/fault-armv.c
index bc0099d5ae85..d0d17b6a3703 100644
--- a/arch/arm/mm/fault-armv.c
+++ b/arch/arm/mm/fault-armv.c
@@ -153,14 +153,11 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte)
page = pfn_to_page(pfn);
mapping = page_mapping(page);
- if (mapping) {
#ifndef CONFIG_SMP
- int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags);
-
- if (dirty)
- __flush_dcache_page(mapping, page);
+ if (test_and_clear_bit(PG_dcache_dirty, &page->flags))
+ __flush_dcache_page(mapping, page);
#endif
-
+ if (mapping) {
if (cache_is_vivt())
make_coherent(mapping, vma, addr, pfn);
else if (vma->vm_flags & VM_EXEC)
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index ae0e25f5a70e..10e06801afb3 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -292,6 +292,11 @@ do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
* down_read()
*/
might_sleep();
+#ifdef CONFIG_DEBUG_VM
+ if (!user_mode(regs) &&
+ !search_exception_tables(regs->ARM_pc))
+ goto no_context;
+#endif
}
fault = __do_page_fault(mm, addr, fsr, tsk);
diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
index 73cae57fa707..30f82fb5918c 100644
--- a/arch/arm/mm/highmem.c
+++ b/arch/arm/mm/highmem.c
@@ -46,6 +46,8 @@ void *kmap_atomic(struct page *page, enum km_type type)
if (!PageHighMem(page))
return page_address(page);
+ debug_kmap_atomic(type);
+
kmap = kmap_high_get(page);
if (kmap)
return kmap;
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 877c492f8e10..40940d7ce4ff 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -483,7 +483,7 @@ free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
/*
* Convert start_pfn/end_pfn to a struct page pointer.
*/
- start_pg = pfn_to_page(start_pfn);
+ start_pg = pfn_to_page(start_pfn - 1) + 1;
end_pg = pfn_to_page(end_pfn);
/*
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/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index fd3154ae69b1..0eb676d7e807 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -829,10 +829,10 @@ EXPORT_SYMBOL(omap_free_dma);
*
* @param arb_rate
* @param max_fifo_depth
- * @param tparams - Number of thereads to reserve : DMA_THREAD_RESERVE_NORM
- * DMA_THREAD_RESERVE_ONET
- * DMA_THREAD_RESERVE_TWOT
- * DMA_THREAD_RESERVE_THREET
+ * @param tparams - Number of threads to reserve : DMA_THREAD_RESERVE_NORM
+ * DMA_THREAD_RESERVE_ONET
+ * DMA_THREAD_RESERVE_TWOT
+ * DMA_THREAD_RESERVE_THREET
*/
void
omap_dma_set_global_params(int arb_rate, int max_fifo_depth, int tparams)
@@ -844,11 +844,14 @@ omap_dma_set_global_params(int arb_rate, int max_fifo_depth, int tparams)
return;
}
+ if (max_fifo_depth == 0)
+ max_fifo_depth = 1;
if (arb_rate == 0)
arb_rate = 1;
- reg = (arb_rate & 0xff) << 16;
- reg |= (0xff & max_fifo_depth);
+ reg = 0xff & max_fifo_depth;
+ reg |= (0x3 & tparams) << 12;
+ reg |= (arb_rate & 0xff) << 16;
dma_write(reg, GCR);
}
diff --git a/arch/arm/plat-omap/include/mach/cpu.h b/arch/arm/plat-omap/include/mach/cpu.h
index 11e73d9e8928..f129efb3075e 100644
--- a/arch/arm/plat-omap/include/mach/cpu.h
+++ b/arch/arm/plat-omap/include/mach/cpu.h
@@ -303,32 +303,21 @@ IS_OMAP_TYPE(3430, 0x3430)
#define cpu_is_omap2430() 0
#define cpu_is_omap3430() 0
-#if defined(MULTI_OMAP1)
-# if defined(CONFIG_ARCH_OMAP730)
-# undef cpu_is_omap730
-# define cpu_is_omap730() is_omap730()
-# endif
-# if defined(CONFIG_ARCH_OMAP850)
-# undef cpu_is_omap850
-# define cpu_is_omap850() is_omap850()
-# endif
-#else
-# if defined(CONFIG_ARCH_OMAP730)
-# undef cpu_is_omap730
-# define cpu_is_omap730() 1
-# endif
-#endif
-#else
-# if defined(CONFIG_ARCH_OMAP850)
-# undef cpu_is_omap850
-# define cpu_is_omap850() 1
-# endif
-#endif
-
/*
* Whether we have MULTI_OMAP1 or not, we still need to distinguish
- * between 330 vs. 1510 and 1611B/5912 vs. 1710.
+ * between 730 vs 850, 330 vs. 1510 and 1611B/5912 vs. 1710.
*/
+
+#if defined(CONFIG_ARCH_OMAP730)
+# undef cpu_is_omap730
+# define cpu_is_omap730() is_omap730()
+#endif
+
+#if defined(CONFIG_ARCH_OMAP850)
+# undef cpu_is_omap850
+# define cpu_is_omap850() is_omap850()
+#endif
+
#if defined(CONFIG_ARCH_OMAP15XX)
# undef cpu_is_omap310
# undef cpu_is_omap1510
@@ -433,3 +422,5 @@ IS_OMAP_TYPE(3430, 0x3430)
int omap_chip_is(struct omap_chip_id oci);
void omap2_check_revision(void);
+
+#endif
diff --git a/arch/arm/plat-omap/include/mach/powerdomain.h b/arch/arm/plat-omap/include/mach/powerdomain.h
index 6271d8556a40..fa6461423bd0 100644
--- a/arch/arm/plat-omap/include/mach/powerdomain.h
+++ b/arch/arm/plat-omap/include/mach/powerdomain.h
@@ -135,6 +135,8 @@ struct powerdomain *pwrdm_lookup(const char *name);
int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
void *user);
+int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
+ void *user);
int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c
index 57f7122a0919..dc3fac3dd0ea 100644
--- a/arch/arm/plat-omap/iovmm.c
+++ b/arch/arm/plat-omap/iovmm.c
@@ -47,7 +47,7 @@
* 'va': mpu virtual address
*
* 'c': contiguous memory area
- * 'd': dicontiguous memory area
+ * 'd': discontiguous memory area
* 'a': anonymous memory allocation
* '()': optional feature
*
@@ -363,8 +363,9 @@ void *da_to_va(struct iommu *obj, u32 da)
goto out;
}
va = area->va;
- mutex_unlock(&obj->mmap_lock);
out:
+ mutex_unlock(&obj->mmap_lock);
+
return va;
}
EXPORT_SYMBOL_GPL(da_to_va);
@@ -398,7 +399,7 @@ static inline void sgtable_drain_vmalloc(struct sg_table *sgt)
{
/*
* Actually this is not necessary at all, just exists for
- * consistency of the code readibility.
+ * consistency of the code readability.
*/
BUG_ON(!sgt);
}
@@ -434,7 +435,7 @@ static inline void sgtable_drain_kmalloc(struct sg_table *sgt)
{
/*
* Actually this is not necessary at all, just exists for
- * consistency of the code readibility
+ * consistency of the code readability
*/
BUG_ON(!sgt);
}
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 88ac9768f1c1..e664b912d7bb 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -595,7 +595,7 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx)
rx &= 1;
if (cpu_is_omap2430() || cpu_is_omap34xx()) {
w = OMAP_MCBSP_READ(io_base, RCCR);
- w |= (tx ? RDISABLE : 0);
+ w |= (rx ? RDISABLE : 0);
OMAP_MCBSP_WRITE(io_base, RCCR, w);
}
w = OMAP_MCBSP_READ(io_base, SPCR1);
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 925f64711c37..75d1f26e5b17 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -270,7 +270,8 @@ void * omap_sram_push(void * start, unsigned long size)
omap_sram_ceil -= size;
omap_sram_ceil = ROUND_DOWN(omap_sram_ceil, sizeof(void *));
memcpy((void *)omap_sram_ceil, start, size);
- flush_icache_range((unsigned long)start, (unsigned long)(start + size));
+ flush_icache_range((unsigned long)omap_sram_ceil,
+ (unsigned long)(omap_sram_ceil + size));
return (void *)omap_sram_ceil;
}
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/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/adc.c b/arch/arm/plat-s3c24xx/adc.c
index 11117a7ba911..4d36b784fb8b 100644
--- a/arch/arm/plat-s3c24xx/adc.c
+++ b/arch/arm/plat-s3c24xx/adc.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
+#include <linux/sched.h>
#include <linux/list.h>
#include <linux/err.h>
#include <linux/clk.h>
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/ADI_BSD.txt b/arch/blackfin/ADI_BSD.txt
new file mode 100644
index 000000000000..501d0b645943
--- /dev/null
+++ b/arch/blackfin/ADI_BSD.txt
@@ -0,0 +1,41 @@
+This BSD-Style License applies to a few files in ./arch/blackfin directory,
+and is included here, so people understand which code they can use outside
+the Linux kernel, in non-GPL based projects.
+
+Using the files released under the "ADI BSD" license, must comply with
+these license terms.
+
+--------------------------------------------------------------------------
+
+Copyright Analog Devices, Inc.
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ - Neither the name of Analog Devices, Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ - The use of this software may or may not infringe the patent rights
+ of one or more patent holders. This license does not release you
+ from the requirement that you obtain separate licenses from these
+ patent holders to use this software.
+
+THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig
index 9a01d445eca8..ae6a60f10120 100644
--- a/arch/blackfin/Kconfig
+++ b/arch/blackfin/Kconfig
@@ -47,6 +47,9 @@ config GENERIC_HARDIRQS
config GENERIC_IRQ_PROBE
def_bool y
+config GENERIC_HARDIRQS_NO__DO_IRQ
+ def_bool y
+
config GENERIC_GPIO
def_bool y
@@ -229,7 +232,7 @@ endchoice
config SMP
depends on BF561
- select GENERIC_TIME
+ select GENERIC_CLOCKEVENTS
bool "Symmetric multi-processing support"
---help---
This enables support for systems with more than one CPU,
@@ -613,12 +616,10 @@ comment "Kernel Timer/Scheduler"
source kernel/Kconfig.hz
config GENERIC_TIME
- bool "Generic time"
- default y
+ def_bool y
config GENERIC_CLOCKEVENTS
bool "Generic clock events"
- depends on GENERIC_TIME
default y
choice
@@ -653,6 +654,10 @@ config GPTMR0_CLOCKSOURCE
depends on GENERIC_CLOCKEVENTS
depends on !TICKSOURCE_GPTMR0
+config ARCH_USES_GETTIMEOFFSET
+ depends on !GENERIC_CLOCKEVENTS
+ def_bool y
+
source kernel/time/Kconfig
comment "Misc"
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/atomic.h b/arch/blackfin/include/asm/atomic.h
index 88f36d599fe8..d27c6274247d 100644
--- a/arch/blackfin/include/asm/atomic.h
+++ b/arch/blackfin/include/asm/atomic.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef __ARCH_BLACKFIN_ATOMIC__
#define __ARCH_BLACKFIN_ATOMIC__
diff --git a/arch/blackfin/include/asm/bfin-global.h b/arch/blackfin/include/asm/bfin-global.h
index aef0594e7865..10064f902d20 100644
--- a/arch/blackfin/include/asm/bfin-global.h
+++ b/arch/blackfin/include/asm/bfin-global.h
@@ -1,29 +1,9 @@
/*
- * File: include/asm-blackfin/bfin-global.h
- * Based on:
- * Author: *
- * Created:
- * Description: Global extern defines for blackfin
+ * Global extern defines for blackfin
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
+ * Copyright 2006-2009 Analog Devices Inc.
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef _BFIN_GLOBAL_H_
diff --git a/arch/blackfin/include/asm/bfin5xx_spi.h b/arch/blackfin/include/asm/bfin5xx_spi.h
index c281c6328276..ed4f8c6db0cd 100644
--- a/arch/blackfin/include/asm/bfin5xx_spi.h
+++ b/arch/blackfin/include/asm/bfin5xx_spi.h
@@ -3,8 +3,6 @@
*
* Copyright 2004-2008 Analog Devices Inc.
*
- * Enter bugs at http://blackfin.uclinux.org/
- *
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/include/asm/bfin_rotary.h b/arch/blackfin/include/asm/bfin_rotary.h
index 425ece64fd5e..abdb2af52902 100644
--- a/arch/blackfin/include/asm/bfin_rotary.h
+++ b/arch/blackfin/include/asm/bfin_rotary.h
@@ -1,6 +1,10 @@
/*
* board initialization should put one of these structures into platform_data
* and place the bfin-rotary onto platform_bus named "bfin-rotary".
+ *
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
*/
#ifndef _BFIN_ROTARY_H
diff --git a/arch/blackfin/include/asm/bfin_simple_timer.h b/arch/blackfin/include/asm/bfin_simple_timer.h
index fccbb595464a..5248c133bc68 100644
--- a/arch/blackfin/include/asm/bfin_simple_timer.h
+++ b/arch/blackfin/include/asm/bfin_simple_timer.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2006-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _bfin_simple_timer_h_
#define _bfin_simple_timer_h_
diff --git a/arch/blackfin/include/asm/bitops.h b/arch/blackfin/include/asm/bitops.h
index daffa71576d4..a2ff3fb3568d 100644
--- a/arch/blackfin/include/asm/bitops.h
+++ b/arch/blackfin/include/asm/bitops.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BLACKFIN_BITOPS_H
#define _BLACKFIN_BITOPS_H
diff --git a/arch/blackfin/include/asm/blackfin.h b/arch/blackfin/include/asm/blackfin.h
index 4d4439583396..eb7c1441d8f9 100644
--- a/arch/blackfin/include/asm/blackfin.h
+++ b/arch/blackfin/include/asm/blackfin.h
@@ -1,6 +1,9 @@
/*
- * Common header file for blackfin family of processors.
+ * Common header file for Blackfin family of processors.
*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
*/
#ifndef _BLACKFIN_H_
diff --git a/arch/blackfin/include/asm/bug.h b/arch/blackfin/include/asm/bug.h
index 655e49540e41..6f4548a13555 100644
--- a/arch/blackfin/include/asm/bug.h
+++ b/arch/blackfin/include/asm/bug.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BLACKFIN_BUG_H
#define _BLACKFIN_BUG_H
diff --git a/arch/blackfin/include/asm/byteorder.h b/arch/blackfin/include/asm/byteorder.h
index 3e69106a4d37..9558416d578b 100644
--- a/arch/blackfin/include/asm/byteorder.h
+++ b/arch/blackfin/include/asm/byteorder.h
@@ -1,6 +1 @@
-#ifndef _BLACKFIN_BYTEORDER_H
-#define _BLACKFIN_BYTEORDER_H
-
#include <linux/byteorder/little_endian.h>
-
-#endif /* _BLACKFIN_BYTEORDER_H */
diff --git a/arch/blackfin/include/asm/cache.h b/arch/blackfin/include/asm/cache.h
index 477050ad5c53..8542bc31f63c 100644
--- a/arch/blackfin/include/asm/cache.h
+++ b/arch/blackfin/include/asm/cache.h
@@ -1,6 +1,9 @@
/*
- * include/asm-blackfin/cache.h
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
*/
+
#ifndef __ARCH_BLACKFIN_CACHE_H
#define __ARCH_BLACKFIN_CACHE_H
@@ -35,10 +38,10 @@
#if defined(CONFIG_SMP) && \
!defined(CONFIG_BFIN_CACHE_COHERENT)
-# if defined(CONFIG_BFIN_ICACHEABLE) || defined(CONFIG_BFIN_L2_ICACHEABLE)
+# if defined(CONFIG_BFIN_EXTMEM_ICACHEABLE) || defined(CONFIG_BFIN_L2_ICACHEABLE)
# define __ARCH_SYNC_CORE_ICACHE
# endif
-# if defined(CONFIG_BFIN_DCACHEABLE) || defined(CONFIG_BFIN_L2_DCACHEABLE)
+# if defined(CONFIG_BFIN_EXTMEM_DCACHEABLE) || defined(CONFIG_BFIN_L2_DCACHEABLE)
# define __ARCH_SYNC_CORE_DCACHE
# endif
#ifndef __ASSEMBLY__
diff --git a/arch/blackfin/include/asm/cacheflush.h b/arch/blackfin/include/asm/cacheflush.h
index 7e55549e180f..af03a36c7a4e 100644
--- a/arch/blackfin/include/asm/cacheflush.h
+++ b/arch/blackfin/include/asm/cacheflush.h
@@ -1,30 +1,9 @@
/*
- * File: include/asm-blackfin/cacheflush.h
- * Based on: include/asm-m68knommu/cacheflush.h
- * Author: LG Soft India
- * Copyright (C) 2004 Analog Devices Inc.
- * Created: Tue Sep 21 2004
- * Description: Blackfin low-level cache routines adapted from the i386
- * and PPC versions by Greg Ungerer (gerg@snapgear.com)
+ * Blackfin low-level cache routines
*
- * Modified:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _BLACKFIN_CACHEFLUSH_H
diff --git a/arch/blackfin/include/asm/cdef_LPBlackfin.h b/arch/blackfin/include/asm/cdef_LPBlackfin.h
index 35f841bce57d..8778e0f03730 100644
--- a/arch/blackfin/include/asm/cdef_LPBlackfin.h
+++ b/arch/blackfin/include/asm/cdef_LPBlackfin.h
@@ -1,30 +1,8 @@
- /*
- * File: include/asm-blackfin/mach-common/cdef_LPBlackfin.h
- * Based on:
- * Author: unknown
- * COPYRIGHT 2005 Analog Devices
- * Created: ?
- * Description:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
+/*
+ * Copyright 2005-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
#ifndef _CDEF_LPBLACKFIN_H
#define _CDEF_LPBLACKFIN_H
diff --git a/arch/blackfin/include/asm/checksum.h b/arch/blackfin/include/asm/checksum.h
index 793581fc9556..a23415be0de1 100644
--- a/arch/blackfin/include/asm/checksum.h
+++ b/arch/blackfin/include/asm/checksum.h
@@ -1,9 +1,14 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ * akbar.hussain@lineo.com
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BFIN_CHECKSUM_H
#define _BFIN_CHECKSUM_H
/*
- * MODIFIED FOR BFIN April 30, 2001 akbar.hussain@lineo.com
- *
* computes the checksum of a memory block at buff, length len,
* and adds in "sum" (32-bit)
*
diff --git a/arch/blackfin/include/asm/clocks.h b/arch/blackfin/include/asm/clocks.h
index 033bba92d61c..f80dad5ff257 100644
--- a/arch/blackfin/include/asm/clocks.h
+++ b/arch/blackfin/include/asm/clocks.h
@@ -1,30 +1,9 @@
/*
- * File: include/asm-blackfin/mach-common/clocks.h
- * Based on: include/asm-blackfin/mach-bf537/bf537.h
- * Author: Robin Getz <rgetz@blackfin.uclinux.org>
+ * Common Clock definitions for various kernel files
*
- * Created: 25Jul07
- * Description: Common Clock definitions for various kernel files
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef _BFIN_CLOCKS_H
diff --git a/arch/blackfin/include/asm/context.S b/arch/blackfin/include/asm/context.S
index f8a664f022b1..5dffaf582a22 100644
--- a/arch/blackfin/include/asm/context.S
+++ b/arch/blackfin/include/asm/context.S
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/kernel/context.S
- * Based on:
- * Author:
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
/*
diff --git a/arch/blackfin/include/asm/cplb.h b/arch/blackfin/include/asm/cplb.h
index d18d16837a6d..fda96261ed62 100644
--- a/arch/blackfin/include/asm/cplb.h
+++ b/arch/blackfin/include/asm/cplb.h
@@ -1,30 +1,7 @@
/*
- * File: include/asm-blackfin/cplb.h
- * Based on: include/asm-blackfin/mach-bf537/bf537.h
- * Author: Robin Getz <rgetz@blackfin.uclinux.org>
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created: 2000
- * Description: Common CPLB definitions for CPLB init
- *
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef _CPLB_H
diff --git a/arch/blackfin/include/asm/cplbinit.h b/arch/blackfin/include/asm/cplbinit.h
index 05b14a631d0c..f315c83a015d 100644
--- a/arch/blackfin/include/asm/cplbinit.h
+++ b/arch/blackfin/include/asm/cplbinit.h
@@ -1,30 +1,9 @@
/*
- * File: include/asm-blackfin/cplbinit.h
- * Based on:
- * Author:
+ * Common CPLB definitions for CPLB init
*
- * Created:
- * Description:
+ * Copyright 2006-2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __ASM_CPLBINIT_H__
diff --git a/arch/blackfin/include/asm/cpu.h b/arch/blackfin/include/asm/cpu.h
index fadfa82f93b2..b191dc662bd8 100644
--- a/arch/blackfin/include/asm/cpu.h
+++ b/arch/blackfin/include/asm/cpu.h
@@ -1,23 +1,8 @@
/*
- * File: arch/blackfin/include/asm/cpu.h.
- * Author: Philippe Gerum <rpm@xenomai.org>
+ * Copyright 2007-2009 Analog Devices Inc.
+ * Philippe Gerum <rpm@xenomai.org>
*
- * Copyright 2007 Analog Devices Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __ASM_BLACKFIN_CPU_H
diff --git a/arch/blackfin/include/asm/def_LPBlackfin.h b/arch/blackfin/include/asm/def_LPBlackfin.h
index 6341eebff3dc..25906468622f 100644
--- a/arch/blackfin/include/asm/def_LPBlackfin.h
+++ b/arch/blackfin/include/asm/def_LPBlackfin.h
@@ -1,32 +1,10 @@
- /*
- * File: include/asm-blackfin/mach-common/def_LPBlackfin.h
- * Based on:
- * Author: unknown
- * COPYRIGHT 2005 Analog Devices
- * Created: ?
- * Description:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-/* LP Blackfin CORE REGISTER BIT & ADDRESS DEFINITIONS FOR ADSP-BF532/33 */
+/*
+ * Blackfin core register bit & address definitions
+ *
+ * Copyright 2005-2008 Analog Devices Inc.
+ *
+ * Licensed under the ADI BSD license or GPL-2 (or later).
+ */
#ifndef _DEF_LPBLACKFIN_H
#define _DEF_LPBLACKFIN_H
diff --git a/arch/blackfin/include/asm/dma-mapping.h b/arch/blackfin/include/asm/dma-mapping.h
index ed6b1f3cccce..7a23d824ac96 100644
--- a/arch/blackfin/include/asm/dma-mapping.h
+++ b/arch/blackfin/include/asm/dma-mapping.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BLACKFIN_DMA_MAPPING_H
#define _BLACKFIN_DMA_MAPPING_H
diff --git a/arch/blackfin/include/asm/dpmc.h b/arch/blackfin/include/asm/dpmc.h
index 96e8208f929a..925e66cb2d49 100644
--- a/arch/blackfin/include/asm/dpmc.h
+++ b/arch/blackfin/include/asm/dpmc.h
@@ -1,9 +1,11 @@
/*
- * include/asm-blackfin/dpmc.h - Miscellaneous IOCTL commands for Dynamic Power
- * Management Controller Driver.
+ * Miscellaneous IOCTL commands for Dynamic Power Management Controller Driver
+ *
* Copyright (C) 2004-2008 Analog Device Inc.
*
+ * Licensed under the GPL-2
*/
+
#ifndef _BLACKFIN_DPMC_H_
#define _BLACKFIN_DPMC_H_
diff --git a/arch/blackfin/include/asm/early_printk.h b/arch/blackfin/include/asm/early_printk.h
index 53a762b6fcd2..68a910db8864 100644
--- a/arch/blackfin/include/asm/early_printk.h
+++ b/arch/blackfin/include/asm/early_printk.h
@@ -1,27 +1,11 @@
/*
- * File: include/asm-blackfin/early_printk.h
- * Author: Robin Getz <rgetz@blackfin.uclinux.org
+ * function prototpyes for early printk
*
- * Created: 14Aug2007
- * Description: function prototpyes for early printk
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Licensed under the GPL-2 or later.
*/
-
#ifndef __ASM_EARLY_PRINTK_H__
#define __ASM_EARLY_PRINTK_H__
diff --git a/arch/blackfin/include/asm/elf.h b/arch/blackfin/include/asm/elf.h
index c823e8ebbfa1..8e0764c81eaf 100644
--- a/arch/blackfin/include/asm/elf.h
+++ b/arch/blackfin/include/asm/elf.h
@@ -1,4 +1,8 @@
-/* Changes made by LG Soft Oct 2004*/
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
#ifndef __ASMBFIN_ELF_H
#define __ASMBFIN_ELF_H
diff --git a/arch/blackfin/include/asm/entry.h b/arch/blackfin/include/asm/entry.h
index 55b808fced71..a6886f6e4819 100644
--- a/arch/blackfin/include/asm/entry.h
+++ b/arch/blackfin/include/asm/entry.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef __BFIN_ENTRY_H
#define __BFIN_ENTRY_H
diff --git a/arch/blackfin/include/asm/fcntl.h b/arch/blackfin/include/asm/fcntl.h
index 9c4037127857..8727b2b382f1 100644
--- a/arch/blackfin/include/asm/fcntl.h
+++ b/arch/blackfin/include/asm/fcntl.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BFIN_FCNTL_H
#define _BFIN_FCNTL_H
diff --git a/arch/blackfin/include/asm/fixed_code.h b/arch/blackfin/include/asm/fixed_code.h
index 32c4d495d847..73fe53e7fd24 100644
--- a/arch/blackfin/include/asm/fixed_code.h
+++ b/arch/blackfin/include/asm/fixed_code.h
@@ -1,5 +1,11 @@
-/* This file defines the fixed addresses where userspace programs can find
- atomic code sequences. */
+/*
+ * This file defines the fixed addresses where userspace programs
+ * can find atomic code sequences.
+ *
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
#ifndef __BFIN_ASM_FIXED_CODE_H__
#define __BFIN_ASM_FIXED_CODE_H__
diff --git a/arch/blackfin/include/asm/flat.h b/arch/blackfin/include/asm/flat.h
index 733a178d782d..c1314c56dd18 100644
--- a/arch/blackfin/include/asm/flat.h
+++ b/arch/blackfin/include/asm/flat.h
@@ -1,8 +1,9 @@
/*
- * include/asm-blackfin/flat.h -- uClinux flat-format executables
+ * uClinux flat-format executables
*
- * Copyright (C) 2003,
+ * Copyright 2003-2009 Analog Devices Inc.
*
+ * Licensed under the GPL-2
*/
#ifndef __BLACKFIN_FLAT_H__
diff --git a/arch/blackfin/include/asm/gpio.h b/arch/blackfin/include/asm/gpio.h
index fe139619351f..5b44d05ca53e 100644
--- a/arch/blackfin/include/asm/gpio.h
+++ b/arch/blackfin/include/asm/gpio.h
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/kernel/bfin_gpio.h
- * Based on:
- * Author: Michael Hennerich (hennerich@blackfin.uclinux.org)
+ * Copyright 2006-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __ARCH_BLACKFIN_GPIO_H__
diff --git a/arch/blackfin/include/asm/hardirq.h b/arch/blackfin/include/asm/hardirq.h
index 0b78b873df51..c078dd78d998 100644
--- a/arch/blackfin/include/asm/hardirq.h
+++ b/arch/blackfin/include/asm/hardirq.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef __BFIN_HARDIRQ_H
#define __BFIN_HARDIRQ_H
diff --git a/arch/blackfin/include/asm/io.h b/arch/blackfin/include/asm/io.h
index 37053eca200e..d1f5029189a7 100644
--- a/arch/blackfin/include/asm/io.h
+++ b/arch/blackfin/include/asm/io.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BFIN_IO_H
#define _BFIN_IO_H
diff --git a/arch/blackfin/include/asm/irq.h b/arch/blackfin/include/asm/irq.h
index 42a15f5ce0d0..e7c0623f9091 100644
--- a/arch/blackfin/include/asm/irq.h
+++ b/arch/blackfin/include/asm/irq.h
@@ -1,17 +1,10 @@
/*
- * 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 2004-2009 Analog Devices Inc.
+ * 2003 HuTao
+ * 2002 Arcturus Networks Inc. (www.arcturusnetworks.com
+ * Ted Ma <mated@sympatico.ca>
*
- * Changed by HuTao Apr18, 2003
- *
- * Copyright was missing when I got the code so took from MIPS arch ...MaTed---
- * Copyright (C) 1994 by Waldorf GMBH, written by Ralf Baechle
- * Copyright (C) 1995, 96, 97, 98, 99, 2000, 2001 by Ralf Baechle
- *
- * Adapted for BlackFin (ADI) by Ted Ma <mated@sympatico.ca>
- * Copyright (c) 2002 Arcturus Networks Inc. (www.arcturusnetworks.com)
- * Copyright (c) 2002 Lineo, Inc. <mattw@lineo.com>
+ * Licensed under the GPL-2
*/
#ifndef _BFIN_IRQ_H_
@@ -19,6 +12,8 @@
#include <linux/irqflags.h>
+#include <mach/anomaly.h>
+
/* SYS_IRQS and NR_IRQS are defined in <mach-bf5xx/irq.h> */
#include <mach/irq.h>
diff --git a/arch/blackfin/include/asm/irq_handler.h b/arch/blackfin/include/asm/irq_handler.h
index 7d9e2d3bbede..7fbe42307b9a 100644
--- a/arch/blackfin/include/asm/irq_handler.h
+++ b/arch/blackfin/include/asm/irq_handler.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2007-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _IRQ_HANDLER_H
#define _IRQ_HANDLER_H
diff --git a/arch/blackfin/include/asm/l1layout.h b/arch/blackfin/include/asm/l1layout.h
index 79dbefaa5bef..c87e68647a2b 100644
--- a/arch/blackfin/include/asm/l1layout.h
+++ b/arch/blackfin/include/asm/l1layout.h
@@ -1,6 +1,9 @@
/*
- * l1layout.h
* Defines a layout of L1 scratchpad memory that userspace can rely on.
+ *
+ * Copyright 2006-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
*/
#ifndef _L1LAYOUT_H_
diff --git a/arch/blackfin/include/asm/linkage.h b/arch/blackfin/include/asm/linkage.h
index 5a822bb790f7..f7d6d47a048d 100644
--- a/arch/blackfin/include/asm/linkage.h
+++ b/arch/blackfin/include/asm/linkage.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef __ASM_LINKAGE_H
#define __ASM_LINKAGE_H
diff --git a/arch/blackfin/include/asm/mmu.h b/arch/blackfin/include/asm/mmu.h
index dbfd686360e6..26f6b70b11e2 100644
--- a/arch/blackfin/include/asm/mmu.h
+++ b/arch/blackfin/include/asm/mmu.h
@@ -1,8 +1,13 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2002 David McCullough <davidm@snapgear.com>
+ *
+ * Licensed under the GPL-2.
+ */
+
#ifndef __MMU_H
#define __MMU_H
-/* Copyright (C) 2002, David McCullough <davidm@snapgear.com> */
-
struct sram_list_struct {
struct sram_list_struct *next;
void *addr;
diff --git a/arch/blackfin/include/asm/mmu_context.h b/arch/blackfin/include/asm/mmu_context.h
index 040410bb07e1..4a3be376ad5b 100644
--- a/arch/blackfin/include/asm/mmu_context.h
+++ b/arch/blackfin/include/asm/mmu_context.h
@@ -1,30 +1,7 @@
/*
- * File: include/asm-blackfin/mmu_context.h
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __BLACKFIN_MMU_CONTEXT_H__
diff --git a/arch/blackfin/include/asm/module.h b/arch/blackfin/include/asm/module.h
index e3128df139d6..9c1cfffddd9b 100644
--- a/arch/blackfin/include/asm/module.h
+++ b/arch/blackfin/include/asm/module.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _ASM_BFIN_MODULE_H
#define _ASM_BFIN_MODULE_H
diff --git a/arch/blackfin/include/asm/mutex.h b/arch/blackfin/include/asm/mutex.h
index 5cc641c50834..f726e3a80ad0 100644
--- a/arch/blackfin/include/asm/mutex.h
+++ b/arch/blackfin/include/asm/mutex.h
@@ -4,6 +4,10 @@
* TODO: implement optimized primitives instead, or leave the generic
* implementation in place, or pick the atomic_xchg() based generic
* implementation. (see asm-generic/mutex-xchg.h for details)
+ *
+ * Copyright 2006-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
*/
#ifndef _ASM_MUTEX_H
diff --git a/arch/blackfin/include/asm/nand.h b/arch/blackfin/include/asm/nand.h
index afbaafa793f1..3ae8b569edfc 100644
--- a/arch/blackfin/include/asm/nand.h
+++ b/arch/blackfin/include/asm/nand.h
@@ -1,13 +1,9 @@
-/* linux/include/asm-blackfin/nand.h
- *
- * Copyright (c) 2007 Analog Devices, Inc.
- * Bryan Wu <bryan.wu@analog.com>
- *
+/*
* BF5XX - NAND flash controller 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.
+ * Copyright 2007-2008 Analog Devices, Inc.
+ *
+ * Licensed under the GPL-2
*/
/* struct bf5xx_nand_platform
diff --git a/arch/blackfin/include/asm/page.h b/arch/blackfin/include/asm/page.h
index 29dcf75c6112..944a07c6cfd6 100644
--- a/arch/blackfin/include/asm/page.h
+++ b/arch/blackfin/include/asm/page.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BLACKFIN_PAGE_H
#define _BLACKFIN_PAGE_H
diff --git a/arch/blackfin/include/asm/page_offset.h b/arch/blackfin/include/asm/page_offset.h
index cbaff24b4b25..d06a89b89d20 100644
--- a/arch/blackfin/include/asm/page_offset.h
+++ b/arch/blackfin/include/asm/page_offset.h
@@ -1,5 +1,10 @@
-
-/* This handles the memory map.. */
+/*
+ * This handles the memory map
+ *
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
#ifdef CONFIG_BLACKFIN
#define PAGE_OFFSET_RAW 0x00000000
diff --git a/arch/blackfin/include/asm/pda.h b/arch/blackfin/include/asm/pda.h
index a6f95695731d..d49bb261d9b7 100644
--- a/arch/blackfin/include/asm/pda.h
+++ b/arch/blackfin/include/asm/pda.h
@@ -1,23 +1,8 @@
/*
- * File: arch/blackfin/include/asm/pda.h
- * Author: Philippe Gerum <rpm@xenomai.org>
+ * Copyright 2007-2009 Analog Devices Inc.
+ * Philippe Gerum <rpm@xenomai.org>
*
- * Copyright 2007 Analog Devices Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef _ASM_BLACKFIN_PDA_H
diff --git a/arch/blackfin/include/asm/pgtable.h b/arch/blackfin/include/asm/pgtable.h
index 783c8f7f8f8c..821c699c2238 100644
--- a/arch/blackfin/include/asm/pgtable.h
+++ b/arch/blackfin/include/asm/pgtable.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BLACKFIN_PGTABLE_H
#define _BLACKFIN_PGTABLE_H
@@ -92,6 +98,12 @@ extern unsigned int kobjsize(const void *objp);
#define VMALLOC_START 0
#define VMALLOC_END 0xffffffff
+/* provide a special get_unmapped_area for framebuffer mmaps of nommu */
+extern unsigned long get_fb_unmapped_area(struct file *filp, unsigned long,
+ unsigned long, unsigned long,
+ unsigned long);
+#define HAVE_ARCH_FB_UNMAPPED_AREA
+
#include <asm-generic/pgtable.h>
#endif /* _BLACKFIN_PGTABLE_H */
diff --git a/arch/blackfin/include/asm/poll.h b/arch/blackfin/include/asm/poll.h
index a0556671357b..072d8966c5c3 100644
--- a/arch/blackfin/include/asm/poll.h
+++ b/arch/blackfin/include/asm/poll.h
@@ -1,3 +1,10 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ *
+ */
+
#ifndef __BFIN_POLL_H
#define __BFIN_POLL_H
diff --git a/arch/blackfin/include/asm/portmux.h b/arch/blackfin/include/asm/portmux.h
index 88eb5c07cc24..edd8ef3a3788 100644
--- a/arch/blackfin/include/asm/portmux.h
+++ b/arch/blackfin/include/asm/portmux.h
@@ -1,6 +1,9 @@
/*
- * Common header file for blackfin family of processors.
+ * Common header file for Blackfin family of processors
*
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
*/
#ifndef _PORTMUX_H_
diff --git a/arch/blackfin/include/asm/posix_types.h b/arch/blackfin/include/asm/posix_types.h
index 80c9d64eb26c..41bc1875c4d7 100644
--- a/arch/blackfin/include/asm/posix_types.h
+++ b/arch/blackfin/include/asm/posix_types.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef __ARCH_BFIN_POSIX_TYPES_H
#define __ARCH_BFIN_POSIX_TYPES_H
diff --git a/arch/blackfin/include/asm/processor.h b/arch/blackfin/include/asm/processor.h
index a36ad8dac068..aea880274de7 100644
--- a/arch/blackfin/include/asm/processor.h
+++ b/arch/blackfin/include/asm/processor.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef __ASM_BFIN_PROCESSOR_H
#define __ASM_BFIN_PROCESSOR_H
diff --git a/arch/blackfin/include/asm/ptrace.h b/arch/blackfin/include/asm/ptrace.h
index e3f086dc7268..27290c955a7a 100644
--- a/arch/blackfin/include/asm/ptrace.h
+++ b/arch/blackfin/include/asm/ptrace.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BFIN_PTRACE_H
#define _BFIN_PTRACE_H
diff --git a/arch/blackfin/include/asm/sections.h b/arch/blackfin/include/asm/sections.h
index ae4dae1e370b..1f5381fbb4a7 100644
--- a/arch/blackfin/include/asm/sections.h
+++ b/arch/blackfin/include/asm/sections.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BLACKFIN_SECTIONS_H
#define _BLACKFIN_SECTIONS_H
diff --git a/arch/blackfin/include/asm/segment.h b/arch/blackfin/include/asm/segment.h
index 02cfd09b5a99..f8e1984ffc7e 100644
--- a/arch/blackfin/include/asm/segment.h
+++ b/arch/blackfin/include/asm/segment.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BFIN_SEGMENT_H
#define _BFIN_SEGMENT_H
diff --git a/arch/blackfin/include/asm/sigcontext.h b/arch/blackfin/include/asm/sigcontext.h
index ce00b03c2775..ce4081a4d815 100644
--- a/arch/blackfin/include/asm/sigcontext.h
+++ b/arch/blackfin/include/asm/sigcontext.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _ASM_BLACKFIN_SIGCONTEXT_H
#define _ASM_BLACKFIN_SIGCONTEXT_H
diff --git a/arch/blackfin/include/asm/siginfo.h b/arch/blackfin/include/asm/siginfo.h
index eca4565cea37..3e81306394e2 100644
--- a/arch/blackfin/include/asm/siginfo.h
+++ b/arch/blackfin/include/asm/siginfo.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BFIN_SIGINFO_H
#define _BFIN_SIGINFO_H
diff --git a/arch/blackfin/include/asm/smp.h b/arch/blackfin/include/asm/smp.h
index 118deeeae7c0..6a0fe94b84a6 100644
--- a/arch/blackfin/include/asm/smp.h
+++ b/arch/blackfin/include/asm/smp.h
@@ -1,23 +1,8 @@
/*
- * File: arch/blackfin/include/asm/smp.h
- * Author: Philippe Gerum <rpm@xenomai.org>
+ * Copyright 2007-2009 Analog Devices Inc.
+ * Philippe Gerum <rpm@xenomai.org>
*
- * Copyright 2007 Analog Devices Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __ASM_BLACKFIN_SMP_H
diff --git a/arch/blackfin/include/asm/spinlock.h b/arch/blackfin/include/asm/spinlock.h
index d6ff4b59fcb1..b0c7f0ee4b03 100644
--- a/arch/blackfin/include/asm/spinlock.h
+++ b/arch/blackfin/include/asm/spinlock.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef __BFIN_SPINLOCK_H
#define __BFIN_SPINLOCK_H
diff --git a/arch/blackfin/include/asm/spinlock_types.h b/arch/blackfin/include/asm/spinlock_types.h
index b1e3c4c7b382..be75762c0610 100644
--- a/arch/blackfin/include/asm/spinlock_types.h
+++ b/arch/blackfin/include/asm/spinlock_types.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef __ASM_SPINLOCK_TYPES_H
#define __ASM_SPINLOCK_TYPES_H
diff --git a/arch/blackfin/include/asm/stat.h b/arch/blackfin/include/asm/stat.h
index d2b6f11ec231..2e27665c4e91 100644
--- a/arch/blackfin/include/asm/stat.h
+++ b/arch/blackfin/include/asm/stat.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2006 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2.
+ */
+
#ifndef _BFIN_STAT_H
#define _BFIN_STAT_H
diff --git a/arch/blackfin/include/asm/string.h b/arch/blackfin/include/asm/string.h
index 321f4d96e4ae..d7f0ccb418c3 100644
--- a/arch/blackfin/include/asm/string.h
+++ b/arch/blackfin/include/asm/string.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BLACKFIN_STRING_H_
#define _BLACKFIN_STRING_H_
diff --git a/arch/blackfin/include/asm/swab.h b/arch/blackfin/include/asm/swab.h
index d442113de515..89de6507ca2b 100644
--- a/arch/blackfin/include/asm/swab.h
+++ b/arch/blackfin/include/asm/swab.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BLACKFIN_SWAB_H
#define _BLACKFIN_SWAB_H
diff --git a/arch/blackfin/include/asm/system.h b/arch/blackfin/include/asm/system.h
index 85e8f16cf8c2..dde19b1d25f5 100644
--- a/arch/blackfin/include/asm/system.h
+++ b/arch/blackfin/include/asm/system.h
@@ -1,34 +1,8 @@
/*
- * File: include/asm/system.h
- * Based on:
- * Author: Tony Kou (tonyko@lineo.ca)
- * Copyright (c) 2002 Arcturus Networks Inc.
- * (www.arcturusnetworks.com)
- * Copyright (c) 2003 Metrowerks (www.metrowerks.com)
- * Copyright (c) 2004 Analog Device Inc.
- * Created: 25Jan2001 - Tony Kou
- * Description: system.h include file
+ * Copyright 2004-2009 Analog Devices Inc.
+ * Tony Kou (tonyko@lineo.ca)
*
- * Modified: 22Sep2006 - Robin Getz
- * - move include blackfin.h down, so I can get access to
- * irq functions in other include files.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _BLACKFIN_SYSTEM_H
diff --git a/arch/blackfin/include/asm/thread_info.h b/arch/blackfin/include/asm/thread_info.h
index 2bbfdd950afc..afb3a8626380 100644
--- a/arch/blackfin/include/asm/thread_info.h
+++ b/arch/blackfin/include/asm/thread_info.h
@@ -1,27 +1,7 @@
/*
- * File: include/asm-blackfin/thread_info.h
- * Based on: include/asm-m68knommu/thread_info.h
- * Author: LG Soft India
- * Copyright (C) 2004-2005 Analog Devices Inc.
- * Created: Tue Sep 21 2004
- * Description: Blackfin low-level thread information
- * Modified:
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _ASM_THREAD_INFO_H
diff --git a/arch/blackfin/include/asm/tlb.h b/arch/blackfin/include/asm/tlb.h
index 89a12ee916d8..a74ae08af1a7 100644
--- a/arch/blackfin/include/asm/tlb.h
+++ b/arch/blackfin/include/asm/tlb.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BLACKFIN_TLB_H
#define _BLACKFIN_TLB_H
diff --git a/arch/blackfin/include/asm/trace.h b/arch/blackfin/include/asm/trace.h
index 312b596b9731..609ad3c84189 100644
--- a/arch/blackfin/include/asm/trace.h
+++ b/arch/blackfin/include/asm/trace.h
@@ -1,6 +1,9 @@
/*
- * Common header file for blackfin family of processors.
+ * header file for hardware trace functions
*
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
*/
#ifndef _BLACKFIN_TRACE_
diff --git a/arch/blackfin/include/asm/traps.h b/arch/blackfin/include/asm/traps.h
index 3cdc454cde23..9fe0da612c09 100644
--- a/arch/blackfin/include/asm/traps.h
+++ b/arch/blackfin/include/asm/traps.h
@@ -1,13 +1,10 @@
/*
- * linux/include/asm/traps.h
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2001 Lineo, Inc
+ * Tony Kou
+ * 1993 Hamish Macdonald
*
- * Copyright (C) 1993 Hamish Macdonald
- *
- * Lineo, Inc Jul 2001 Tony Kou
- *
- * 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.
+ * Licensed under the GPL-2
*/
#ifndef _BFIN_TRAPS_H
diff --git a/arch/blackfin/include/asm/uaccess.h b/arch/blackfin/include/asm/uaccess.h
index 2f469a1f80fb..c03b8532aad3 100644
--- a/arch/blackfin/include/asm/uaccess.h
+++ b/arch/blackfin/include/asm/uaccess.h
@@ -1,4 +1,7 @@
-/* Changes made by Lineo Inc. May 2001
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
*
* Based on: include/asm-m68knommu/uaccess.h
*/
diff --git a/arch/blackfin/include/asm/unistd.h b/arch/blackfin/include/asm/unistd.h
index 02b1529dad57..779be02a910a 100644
--- a/arch/blackfin/include/asm/unistd.h
+++ b/arch/blackfin/include/asm/unistd.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef __ASM_BFIN_UNISTD_H
#define __ASM_BFIN_UNISTD_H
/*
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c
index f05d1b99b0ef..bd32c09b9349 100644
--- a/arch/blackfin/kernel/asm-offsets.c
+++ b/arch/blackfin/kernel/asm-offsets.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/kernel/asm-offsets.c
- * Based on:
- * Author:
+ * generate definitions needed by assembly language modules
*
- * Created:
- * Description: generate definitions needed by assembly language modules.
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#include <linux/stddef.h>
diff --git a/arch/blackfin/kernel/bfin_dma_5xx.c b/arch/blackfin/kernel/bfin_dma_5xx.c
index 384868dedac3..1f170216d2f9 100644
--- a/arch/blackfin/kernel/bfin_dma_5xx.c
+++ b/arch/blackfin/kernel/bfin_dma_5xx.c
@@ -2,6 +2,7 @@
* bfin_dma_5xx.c - Blackfin DMA implementation
*
* Copyright 2004-2008 Analog Devices Inc.
+ *
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index fc4681c0170e..22705eeff34f 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/kernel/bfin_gpio.c
- * Based on:
- * Author: Michael Hennerich (hennerich@blackfin.uclinux.org)
+ * GPIO Abstraction Layer
*
- * Created:
- * Description: GPIO Abstraction Layer
+ * Copyright 2006-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#include <linux/delay.h>
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbinit.c b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
index 36193eed9a1f..f7b9cdce8239 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbinit.c
@@ -1,25 +1,11 @@
/*
* Blackfin CPLB initialization
*
- * Copyright 2004-2007 Analog Devices Inc.
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
+
#include <linux/module.h>
#include <asm/blackfin.h>
diff --git a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
index 8e1e9e9e9632..69e0e530d70f 100644
--- a/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-mpu/cplbmgr.c
@@ -1,22 +1,11 @@
/*
- * Blackfin CPLB exception handling.
- * Copyright 2004-2007 Analog Devices Inc.
+ * Blackfin CPLB exception handling for when MPU in on
*
- * This 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.
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
+
#include <linux/module.h>
#include <linux/mm.h>
diff --git a/arch/blackfin/kernel/cplb-nompu/cplbinit.c b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
index 5d8ad503f82a..fd9a2f31e686 100644
--- a/arch/blackfin/kernel/cplb-nompu/cplbinit.c
+++ b/arch/blackfin/kernel/cplb-nompu/cplbinit.c
@@ -1,24 +1,9 @@
/*
* Blackfin CPLB initialization
*
- * Copyright 2004-2007 Analog Devices Inc.
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
diff --git a/arch/blackfin/kernel/cplb-nompu/cplbmgr.c b/arch/blackfin/kernel/cplb-nompu/cplbmgr.c
index d9ea46c6e41a..5b88861d6183 100644
--- a/arch/blackfin/kernel/cplb-nompu/cplbmgr.c
+++ b/arch/blackfin/kernel/cplb-nompu/cplbmgr.c
@@ -1,26 +1,14 @@
/*
- * File: arch/blackfin/kernel/cplb-nompu-c/cplbmgr.c
* Based on: arch/blackfin/kernel/cplb-mpu/cplbmgr.c
* Author: Michael McTernan <mmcternan@airvana.com>
*
- * Created: 01Nov2008
* Description: CPLB miss handler.
*
* Modified:
* Copyright 2008 Airvana Inc.
- * Copyright 2004-2007 Analog Devices Inc.
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Licensed under the GPL-2 or later
*/
#include <linux/kernel.h>
diff --git a/arch/blackfin/kernel/cplbinfo.c b/arch/blackfin/kernel/cplbinfo.c
index 64d78300dd08..0bdaa517a501 100644
--- a/arch/blackfin/kernel/cplbinfo.c
+++ b/arch/blackfin/kernel/cplbinfo.c
@@ -2,6 +2,7 @@
* arch/blackfin/kernel/cplbinfo.c - display CPLB status
*
* Copyright 2004-2008 Analog Devices Inc.
+ *
* Licensed under the GPL-2 or later.
*/
@@ -111,24 +112,21 @@ static const struct seq_operations cplbinfo_sops = {
.show = cplbinfo_show,
};
+#define CPLBINFO_DCPLB_FLAG 0x80000000
+
static int cplbinfo_open(struct inode *inode, struct file *file)
{
- char buf[256], *path, *p;
+ struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode);
+ char cplb_type;
unsigned int cpu;
- char *s_cpu, *s_cplb;
int ret;
struct seq_file *m;
struct cplbinfo_data *cdata;
- path = d_path(&file->f_path, buf, sizeof(buf));
- if (IS_ERR(path))
- return PTR_ERR(path);
- s_cpu = strstr(path, "/cpu");
- s_cplb = strrchr(path, '/');
- if (!s_cpu || !s_cplb)
- return -EINVAL;
+ cpu = (unsigned int)pde->data;
+ cplb_type = cpu & CPLBINFO_DCPLB_FLAG ? 'D' : 'I';
+ cpu &= ~CPLBINFO_DCPLB_FLAG;
- cpu = simple_strtoul(s_cpu + 4, &p, 10);
if (!cpu_online(cpu))
return -ENODEV;
@@ -139,7 +137,7 @@ static int cplbinfo_open(struct inode *inode, struct file *file)
cdata = m->private;
cdata->pos = 0;
- cdata->cplb_type = toupper(s_cplb[1]);
+ cdata->cplb_type = cplb_type;
cplbinfo_seq_init(cdata, cpu);
return 0;
@@ -168,8 +166,10 @@ static int __init cplbinfo_init(void)
if (!cpu_dir)
return -ENOMEM;
- proc_create("icplb", S_IRUGO, cpu_dir, &cplbinfo_fops);
- proc_create("dcplb", S_IRUGO, cpu_dir, &cplbinfo_fops);
+ proc_create_data("icplb", S_IRUGO, cpu_dir, &cplbinfo_fops,
+ (void *)cpu);
+ proc_create_data("dcplb", S_IRUGO, cpu_dir, &cplbinfo_fops,
+ (void *)(cpu | CPLBINFO_DCPLB_FLAG));
}
return 0;
diff --git a/arch/blackfin/kernel/dma-mapping.c b/arch/blackfin/kernel/dma-mapping.c
index 2f62a9f4058a..e74e74d7733f 100644
--- a/arch/blackfin/kernel/dma-mapping.c
+++ b/arch/blackfin/kernel/dma-mapping.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/kernel/dma-mapping.c
- * Based on:
- * Author:
+ * Dynamic DMA mapping support
*
- * Created:
- * Description: Dynamic DMA mapping support.
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#include <linux/types.h>
diff --git a/arch/blackfin/kernel/early_printk.c b/arch/blackfin/kernel/early_printk.c
index 931c78b5ea1f..84ed8375113c 100644
--- a/arch/blackfin/kernel/early_printk.c
+++ b/arch/blackfin/kernel/early_printk.c
@@ -1,25 +1,10 @@
/*
- * File: arch/blackfin/kernel/early_printk.c
- * Based on: arch/x86_64/kernel/early_printk.c
- * Author: Robin Getz <rgetz@blackfin.uclinux.org
+ * allow a console to be used for early printk
+ * derived from arch/x86/kernel/early_printk.c
*
- * Created: 14Aug2007
- * Description: allow a console to be used for early printk
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Licensed under the GPL-2
*/
#include <linux/kernel.h>
diff --git a/arch/blackfin/kernel/entry.S b/arch/blackfin/kernel/entry.S
index 3f8769b7db54..f27dc2292e1b 100644
--- a/arch/blackfin/kernel/entry.S
+++ b/arch/blackfin/kernel/entry.S
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/kernel/entry.S
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#include <linux/linkage.h>
diff --git a/arch/blackfin/kernel/fixed_code.S b/arch/blackfin/kernel/fixed_code.S
index 0d2d9e0968c8..0565917f23ba 100644
--- a/arch/blackfin/kernel/fixed_code.S
+++ b/arch/blackfin/kernel/fixed_code.S
@@ -6,7 +6,12 @@
* These are aligned to 16 bytes, so that we have some space to replace
* these sequences with something else (e.g. kernel traps if we ever do
* BF561 SMP).
+ *
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
*/
+
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/unistd.h>
diff --git a/arch/blackfin/kernel/flat.c b/arch/blackfin/kernel/flat.c
index d188b2430536..a88daddbf074 100644
--- a/arch/blackfin/kernel/flat.c
+++ b/arch/blackfin/kernel/flat.c
@@ -1,21 +1,7 @@
/*
- * arch/blackfin/kernel/flat.c
+ * Copyright 2007 Analog Devices Inc.
*
- * Copyright (C) 2007 Analog Devices, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You 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
+ * Licensed under the GPL-2.
*/
#include <linux/module.h>
diff --git a/arch/blackfin/kernel/init_task.c b/arch/blackfin/kernel/init_task.c
index c26c34de9f3c..118c5b9dedac 100644
--- a/arch/blackfin/kernel/init_task.c
+++ b/arch/blackfin/kernel/init_task.c
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/kernel/init_task.c
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description: This file contains the simple DMA Implementation for Blackfin
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#include <linux/mm.h>
diff --git a/arch/blackfin/kernel/irqchip.c b/arch/blackfin/kernel/irqchip.c
index 4b5fd36187d9..db9f9c91f11f 100644
--- a/arch/blackfin/kernel/irqchip.c
+++ b/arch/blackfin/kernel/irqchip.c
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/kernel/irqchip.c
- * Based on:
- * Author:
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Created:
- * Description: This file contains the simple DMA Implementation for Blackfin
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#include <linux/kernel_stat.h>
diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c
index 67fc7a56c865..a6dfa6b71e63 100644
--- a/arch/blackfin/kernel/module.c
+++ b/arch/blackfin/kernel/module.c
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/kernel/module.c
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#define pr_fmt(fmt) "module %s: " fmt
diff --git a/arch/blackfin/kernel/process.c b/arch/blackfin/kernel/process.c
index f5b286189647..430ae39456e8 100644
--- a/arch/blackfin/kernel/process.c
+++ b/arch/blackfin/kernel/process.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/kernel/process.c
- * Based on:
- * Author:
+ * Blackfin architecture-dependent process handling
*
- * Created:
- * Description: Blackfin architecture-dependent process handling.
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#include <linux/module.h>
diff --git a/arch/blackfin/kernel/ptrace.c b/arch/blackfin/kernel/ptrace.c
index 30f4828277ad..0982b5d5af10 100644
--- a/arch/blackfin/kernel/ptrace.c
+++ b/arch/blackfin/kernel/ptrace.c
@@ -1,30 +1,8 @@
/*
- * File: arch/blackfin/kernel/ptrace.c
- * Based on: Taken from linux/kernel/ptrace.c
- * Author: linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ * linux/kernel/ptrace.c is by Ross Biro 1/23/92, edited by Linus Torvalds
+ * these modifications are Copyright 2004-2009 Analog Devices Inc.
*
- * Created: 1/23/92
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2
*/
#include <linux/kernel.h>
diff --git a/arch/blackfin/kernel/setup.c b/arch/blackfin/kernel/setup.c
index 369535b61ed1..c202a44d1416 100644
--- a/arch/blackfin/kernel/setup.c
+++ b/arch/blackfin/kernel/setup.c
@@ -1,9 +1,5 @@
/*
- * arch/blackfin/kernel/setup.c
- *
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Enter bugs at http://blackfin.uclinux.org/
+ * Copyright 2004-2009 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/kernel/shadow_console.c b/arch/blackfin/kernel/shadow_console.c
index 8b8c7107a162..557e9fef406a 100644
--- a/arch/blackfin/kernel/shadow_console.c
+++ b/arch/blackfin/kernel/shadow_console.c
@@ -4,8 +4,6 @@
*
* Copyright 2009 Analog Devices Inc.
*
- * Enter bugs at http://blackfin.uclinux.org/
- *
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index dbc3bbf846be..9d90c18fab23 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/kernel/signal.c
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#include <linux/signal.h>
diff --git a/arch/blackfin/kernel/sys_bfin.c b/arch/blackfin/kernel/sys_bfin.c
index 3da60fb13ce4..afcef129d4e8 100644
--- a/arch/blackfin/kernel/sys_bfin.c
+++ b/arch/blackfin/kernel/sys_bfin.c
@@ -1,32 +1,10 @@
/*
- * File: arch/blackfin/kernel/sys_bfin.c
- * Based on:
- * Author:
+ * contains various random system calls that have a non-standard
+ * calling sequence on the Linux/Blackfin platform.
*
- * Created:
- * Description: This file contains various random system calls that
- * have a non-standard calling sequence on the Linux/bfin
- * platform.
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#include <linux/spinlock.h>
@@ -91,3 +69,14 @@ asmlinkage void *sys_dma_memcpy(void *dest, const void *src, size_t len)
{
return safe_dma_memcpy(dest, src, len);
}
+
+#if defined(CONFIG_FB) || defined(CONFIG_FB_MODULE)
+#include <linux/fb.h>
+unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ struct fb_info *info = filp->private_data;
+ return (unsigned long)info->screen_base;
+}
+EXPORT_SYMBOL(get_fb_unmapped_area);
+#endif
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c
index f9715764383e..359cfb1815ca 100644
--- a/arch/blackfin/kernel/time-ts.c
+++ b/arch/blackfin/kernel/time-ts.c
@@ -1,13 +1,13 @@
/*
- * linux/arch/kernel/time-ts.c
- *
* Based on arm clockevents implementation and old bfin time tick.
*
- * Copyright(C) 2008, GeoTechnologies, Vitja Makarov
+ * Copyright 2008-2009 Analog Devics Inc.
+ * 2008 GeoTechnologies
+ * Vitja Makarov
*
- * This code is licenced under the GPL version 2. For details see
- * kernel-base/COPYING.
+ * Licensed under the GPL-2
*/
+
#include <linux/module.h>
#include <linux/profile.h>
#include <linux/interrupt.h>
diff --git a/arch/blackfin/kernel/time.c b/arch/blackfin/kernel/time.c
index adb54aa7d7c8..bd3b53da295e 100644
--- a/arch/blackfin/kernel/time.c
+++ b/arch/blackfin/kernel/time.c
@@ -14,6 +14,7 @@
#include <linux/time.h>
#include <linux/irq.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#include <asm/blackfin.h>
#include <asm/time.h>
@@ -81,11 +82,11 @@ time_sched_init(irqreturn_t(*timer_routine) (int, void *))
#endif
}
+#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
/*
* Should return useconds since last timer tick
*/
-#ifndef CONFIG_GENERIC_TIME
-static unsigned long gettimeoffset(void)
+u32 arch_gettimeoffset(void)
{
unsigned long offset;
unsigned long clocks_per_jiffy;
@@ -184,65 +185,6 @@ void __init time_init(void)
time_sched_init(timer_interrupt);
}
-#ifndef CONFIG_GENERIC_TIME
-void do_gettimeofday(struct timeval *tv)
-{
- unsigned long flags;
- unsigned long seq;
- unsigned long usec, sec;
-
- do {
- seq = read_seqbegin_irqsave(&xtime_lock, flags);
- usec = gettimeoffset();
- sec = xtime.tv_sec;
- usec += (xtime.tv_nsec / NSEC_PER_USEC);
- }
- while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
- while (usec >= USEC_PER_SEC) {
- usec -= USEC_PER_SEC;
- sec++;
- }
-
- tv->tv_sec = sec;
- tv->tv_usec = usec;
-}
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
- time_t wtm_sec, sec = tv->tv_sec;
- long wtm_nsec, nsec = tv->tv_nsec;
-
- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
- return -EINVAL;
-
- write_seqlock_irq(&xtime_lock);
- /*
- * This is revolting. We need to set the xtime.tv_usec
- * correctly. However, the value in this location is
- * is value at the last tick.
- * Discover what correction gettimeofday
- * would have done, and then undo it!
- */
- nsec -= (gettimeoffset() * NSEC_PER_USEC);
-
- wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
- wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
- set_normalized_timespec(&xtime, sec, nsec);
- set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
- ntp_clear();
-
- write_sequnlock_irq(&xtime_lock);
- clock_was_set();
-
- return 0;
-}
-EXPORT_SYMBOL(do_settimeofday);
-#endif /* !CONFIG_GENERIC_TIME */
-
/*
* Scheduler clock - returns current time in nanosec units.
*/
diff --git a/arch/blackfin/kernel/traps.c b/arch/blackfin/kernel/traps.c
index 56464cb8edf3..6b7325d634af 100644
--- a/arch/blackfin/kernel/traps.c
+++ b/arch/blackfin/kernel/traps.c
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/kernel/traps.c
- * Based on:
- * Author: Hamish Macdonald
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description: uses S/W interrupt 15 for the system calls
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#include <linux/bug.h>
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
index ffd90fbbc8f9..10e12539000e 100644
--- a/arch/blackfin/kernel/vmlinux.lds.S
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/kernel/vmlinux.lds.S
- * Based on: none - original work
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created: Tue Sep 21 2004
- * Description: Master linker script for blackfin architecture
- *
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#define VMLINUX_SYMBOL(_sym_) _##_sym_
diff --git a/arch/blackfin/lib/ashldi3.c b/arch/blackfin/lib/ashldi3.c
index a8c279e9b192..ab69d8768afc 100644
--- a/arch/blackfin/lib/ashldi3.c
+++ b/arch/blackfin/lib/ashldi3.c
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/lib/ashldi3.c
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include "gcclib.h"
diff --git a/arch/blackfin/lib/ashrdi3.c b/arch/blackfin/lib/ashrdi3.c
index a0d3419329ca..b5b351e82e10 100644
--- a/arch/blackfin/lib/ashrdi3.c
+++ b/arch/blackfin/lib/ashrdi3.c
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/lib/ashrdi3.c
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include "gcclib.h"
diff --git a/arch/blackfin/lib/checksum.c b/arch/blackfin/lib/checksum.c
index cd605e7d8518..c62969dc1bbb 100644
--- a/arch/blackfin/lib/checksum.c
+++ b/arch/blackfin/lib/checksum.c
@@ -1,32 +1,12 @@
/*
- * File: arch/blackfin/lib/checksum.c
- * Based on: none - original work
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description: An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
+ * Licensed under the GPL-2 or later.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
+ * An implementation of the TCP/IP protocol suite for the LINUX operating
+ * system. INET is implemented using the BSD Socket interface as the
+ * means of communication with the user level.
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/module.h>
diff --git a/arch/blackfin/lib/divsi3.S b/arch/blackfin/lib/divsi3.S
index 2ac59c70dd94..f89c5a49c47b 100644
--- a/arch/blackfin/lib/divsi3.S
+++ b/arch/blackfin/lib/divsi3.S
@@ -1,10 +1,9 @@
/*
- * File: arch/blackfin/lib/divsi3.S
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description: 16 / 32 bit signed division.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
+ *
+ * 16 / 32 bit signed division.
* Special cases :
* 1) If(numerator == 0)
* return 0
@@ -22,25 +21,6 @@
* R0 - Quotient (o)
* Registers Used : R2-R7,P0-P2
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
.global ___divsi3;
diff --git a/arch/blackfin/lib/gcclib.h b/arch/blackfin/lib/gcclib.h
index 9ccd39a135ee..724f07f14f8d 100644
--- a/arch/blackfin/lib/gcclib.h
+++ b/arch/blackfin/lib/gcclib.h
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/lib/gcclib.h
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#define BITS_PER_UNIT 8
diff --git a/arch/blackfin/lib/lshrdi3.c b/arch/blackfin/lib/lshrdi3.c
index e57bf6fbdf3f..53f1741047e5 100644
--- a/arch/blackfin/lib/lshrdi3.c
+++ b/arch/blackfin/lib/lshrdi3.c
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/lib/lshrdi3.c
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include "gcclib.h"
diff --git a/arch/blackfin/lib/memchr.S b/arch/blackfin/lib/memchr.S
index 5da428134d32..542e40f8775f 100644
--- a/arch/blackfin/lib/memchr.S
+++ b/arch/blackfin/lib/memchr.S
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/lib/memchr.S
- * Based on:
- * Author:
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#include <linux/linkage.h>
diff --git a/arch/blackfin/lib/memcmp.S b/arch/blackfin/lib/memcmp.S
index 219fa2877c62..ce5b9f1a8267 100644
--- a/arch/blackfin/lib/memcmp.S
+++ b/arch/blackfin/lib/memcmp.S
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/lib/memcmp.S
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#include <linux/linkage.h>
diff --git a/arch/blackfin/lib/memcpy.S b/arch/blackfin/lib/memcpy.S
index e654a18a0754..c31bf22aab19 100644
--- a/arch/blackfin/lib/memcpy.S
+++ b/arch/blackfin/lib/memcpy.S
@@ -1,36 +1,13 @@
/*
- * File: arch/blackfin/lib/memcpy.S
- * Based on:
- * Author:
+ * internal version of memcpy(), issued by the compiler to copy blocks of
+ * data around. This is really memmove() - it has to be able to deal with
+ * possible overlaps, because that ambiguity is when the compiler gives up
+ * and calls a function. We have our own, internal version so that we get
+ * something we trust, even if the user has redefined the normal symbol.
*
- * Created:
- * Description: internal version of memcpy(), issued by the compiler
- * to copy blocks of data around.
- * This is really memmove() - it has to be able to deal with
- * possible overlaps, because that ambiguity is when the compiler
- * gives up and calls a function. We have our own, internal version
- * so that we get something we trust, even if the user has redefined
- * the normal symbol.
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#include <linux/linkage.h>
diff --git a/arch/blackfin/lib/memmove.S b/arch/blackfin/lib/memmove.S
index 33f8653145b7..80c240acac60 100644
--- a/arch/blackfin/lib/memmove.S
+++ b/arch/blackfin/lib/memmove.S
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/lib/memmove.S
- * Based on:
- * Author:
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#include <linux/linkage.h>
diff --git a/arch/blackfin/lib/memset.S b/arch/blackfin/lib/memset.S
index 8159136a29ea..c30d99b10969 100644
--- a/arch/blackfin/lib/memset.S
+++ b/arch/blackfin/lib/memset.S
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/lib/memset.S
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#include <linux/linkage.h>
diff --git a/arch/blackfin/lib/modsi3.S b/arch/blackfin/lib/modsi3.S
index ca1dd3973b39..8b0c7d4052af 100644
--- a/arch/blackfin/lib/modsi3.S
+++ b/arch/blackfin/lib/modsi3.S
@@ -1,36 +1,12 @@
/*
- * File: arch/blackfin/lib/modsi3.S
- * Based on:
- * Author:
+ * This program computes 32 bit signed remainder. It calls div32 function
+ * for quotient estimation.
+ * Registers in: R0, R1 = Numerator/ Denominator
+ * Registers out: R0 = Remainder
*
- * Created:
- * Description: This program computes 32 bit signed remainder. It calls div32 function
- * for quotient estimation.
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Registers used :
- * Numerator/ Denominator in R0, R1
- * R0 - returns remainder.
- * R2-R7
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
.global ___modsi3;
diff --git a/arch/blackfin/lib/muldi3.S b/arch/blackfin/lib/muldi3.S
index abde120ee230..953a38a1d1d1 100644
--- a/arch/blackfin/lib/muldi3.S
+++ b/arch/blackfin/lib/muldi3.S
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2008 Analog Devices Inc.
+ *
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
+ */
+
.align 2
.global ___muldi3;
.type ___muldi3, STT_FUNC;
diff --git a/arch/blackfin/lib/outs.S b/arch/blackfin/lib/outs.S
index 4685b7aa0080..250f4d4b9436 100644
--- a/arch/blackfin/lib/outs.S
+++ b/arch/blackfin/lib/outs.S
@@ -1,30 +1,11 @@
/*
- * File: arch/blackfin/lib/outs.S
- * Based on:
- * Author: Bas Vermeulen <bas@buyways.nl>
+ * Implementation of outs{bwl} for BlackFin processors using zero overhead loops.
*
- * Created: Tue Mar 22 15:27:24 CEST 2005
- * Description: Implementation of outs{bwl} for BlackFin processors using zero overhead loops.
+ * Copyright 2005-2009 Analog Devices Inc.
+ * 2005 BuyWays BV
+ * Bas Vermeulen <bas@buyways.nl>
*
- * Modified: Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl>
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2.
*/
#include <linux/linkage.h>
diff --git a/arch/blackfin/lib/smulsi3_highpart.S b/arch/blackfin/lib/smulsi3_highpart.S
index e383cd3eca5d..99ee8c5de38b 100644
--- a/arch/blackfin/lib/smulsi3_highpart.S
+++ b/arch/blackfin/lib/smulsi3_highpart.S
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2007 Analog Devices Inc.
+ *
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
+ */
+
.align 2
.global ___smulsi3_highpart;
.type ___smulsi3_highpart, STT_FUNC;
diff --git a/arch/blackfin/lib/udivsi3.S b/arch/blackfin/lib/udivsi3.S
index 58fd96d74766..97e904315ec6 100644
--- a/arch/blackfin/lib/udivsi3.S
+++ b/arch/blackfin/lib/udivsi3.S
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/lib/udivsi3.S
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#include <linux/linkage.h>
diff --git a/arch/blackfin/lib/umodsi3.S b/arch/blackfin/lib/umodsi3.S
index 4f2b76ee7626..168eba7c64c8 100644
--- a/arch/blackfin/lib/umodsi3.S
+++ b/arch/blackfin/lib/umodsi3.S
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/lib/umodsi3.S
- * Based on:
- * Author:
+ * libgcc1 routines for Blackfin 5xx
*
- * Created:
- * Description: libgcc1 routines for Blackfin 5xx
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifdef CONFIG_ARITHMETIC_OPS_L1
diff --git a/arch/blackfin/lib/umulsi3_highpart.S b/arch/blackfin/lib/umulsi3_highpart.S
index 67b799351e3e..051824a6ed00 100644
--- a/arch/blackfin/lib/umulsi3_highpart.S
+++ b/arch/blackfin/lib/umulsi3_highpart.S
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2007 Analog Devices Inc.
+ *
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
+ */
+
.align 2
.global ___umulsi3_highpart;
.type ___umulsi3_highpart, STT_FUNC;
diff --git a/arch/blackfin/mach-bf518/boards/ezbrd.c b/arch/blackfin/mach-bf518/boards/ezbrd.c
index 03e4a9941f01..01975c017116 100644
--- a/arch/blackfin/mach-bf518/boards/ezbrd.c
+++ b/arch/blackfin/mach-bf518/boards/ezbrd.c
@@ -1,31 +1,9 @@
/*
- * File: arch/blackfin/mach-bf518/boards/ezbrd.c
- * Based on: arch/blackfin/mach-bf527/boards/ezbrd.c
- * Author: Bryan Wu <cooloney@kernel.org>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -571,19 +549,6 @@ static struct platform_device bf51x_sdh_device = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
static const unsigned int cclk_vlev_datasheet[] =
{
VRPAIR(VLEV_100, 400000000),
@@ -660,8 +625,6 @@ static struct platform_device *stamp_devices[] __initdata = {
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
&ezbrd_flash_device,
#endif
-
- &bfin_gpios_device,
};
static int __init ezbrd_init(void)
diff --git a/arch/blackfin/mach-bf518/dma.c b/arch/blackfin/mach-bf518/dma.c
index 698e88ca5104..78b43605a0b5 100644
--- a/arch/blackfin/mach-bf518/dma.c
+++ b/arch/blackfin/mach-bf518/dma.c
@@ -1,31 +1,11 @@
/*
- * File: arch/blackfin/mach-bf518/dma.c
- * Based on:
- * Author: Bryan Wu <cooloney@kernel.org>
+ * the simple DMA Implementation for Blackfin
*
- * Created:
- * Description: This file contains the simple DMA Implementation for Blackfin
+ * Copyright 2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
+
#include <linux/module.h>
#include <asm/blackfin.h>
diff --git a/arch/blackfin/mach-bf518/include/mach/bf518.h b/arch/blackfin/mach-bf518/include/mach/bf518.h
index 78da1a07ee73..856b330ecf0b 100644
--- a/arch/blackfin/mach-bf518/include/mach/bf518.h
+++ b/arch/blackfin/mach-bf518/include/mach/bf518.h
@@ -1,30 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/bf518.h
- * Based on: include/asm-blackfin/mach-bf527/bf527.h
- * Author: Michael Hennerich (michael.hennerich@analog.com)
+ * Copyright 2008 Analog Devices Inc.
*
- * Created:
- * Description: SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF518
- *
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __MACH_BF518_H__
diff --git a/arch/blackfin/mach-bf518/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf518/include/mach/bfin_serial_5xx.h
index dbade93395eb..970d310021e7 100644
--- a/arch/blackfin/mach-bf518/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf518/include/mach/bfin_serial_5xx.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf518/bfin_serial_5xx.h
- * based on:
- * author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * created:
- * description:
- * blackfin serial driver head file
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later
*/
#include <linux/serial.h>
diff --git a/arch/blackfin/mach-bf518/include/mach/blackfin.h b/arch/blackfin/mach-bf518/include/mach/blackfin.h
index 83421d393148..6cfb246aebec 100644
--- a/arch/blackfin/mach-bf518/include/mach/blackfin.h
+++ b/arch/blackfin/mach-bf518/include/mach/blackfin.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/blackfin.h
- * Based on:
- * Author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _MACH_BLACKFIN_H_
diff --git a/arch/blackfin/mach-bf518/include/mach/cdefBF512.h b/arch/blackfin/mach-bf518/include/mach/cdefBF512.h
index 820c13c4daaa..493020d0a65a 100644
--- a/arch/blackfin/mach-bf518/include/mach/cdefBF512.h
+++ b/arch/blackfin/mach-bf518/include/mach/cdefBF512.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/cdefbf512.h
- * Based on:
- * Author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Created:
- * Description: system mmr register map
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _CDEF_BF512_H
diff --git a/arch/blackfin/mach-bf518/include/mach/cdefBF514.h b/arch/blackfin/mach-bf518/include/mach/cdefBF514.h
index dfe492dfe54e..e1d99911025d 100644
--- a/arch/blackfin/mach-bf518/include/mach/cdefBF514.h
+++ b/arch/blackfin/mach-bf518/include/mach/cdefBF514.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/cdefbf514.h
- * Based on:
- * Author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Created:
- * Description: system mmr register map
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _CDEF_BF514_H
diff --git a/arch/blackfin/mach-bf518/include/mach/cdefBF516.h b/arch/blackfin/mach-bf518/include/mach/cdefBF516.h
index 14df43d4677a..6b364eda4947 100644
--- a/arch/blackfin/mach-bf518/include/mach/cdefBF516.h
+++ b/arch/blackfin/mach-bf518/include/mach/cdefBF516.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/cdefbf516.h
- * Based on:
- * Author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Created:
- * Description: system mmr register map
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _CDEF_BF516_H
diff --git a/arch/blackfin/mach-bf518/include/mach/cdefBF518.h b/arch/blackfin/mach-bf518/include/mach/cdefBF518.h
index bafb370cfb3c..929b90650bd4 100644
--- a/arch/blackfin/mach-bf518/include/mach/cdefBF518.h
+++ b/arch/blackfin/mach-bf518/include/mach/cdefBF518.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/cdefbf518.h
- * Based on:
- * Author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Created:
- * Description: system mmr register map
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _CDEF_BF518_H
@@ -211,6 +186,47 @@
#define bfin_read_EMAC_TXC_ABORT() bfin_read32(EMAC_TXC_ABORT)
#define bfin_write_EMAC_TXC_ABORT(val) bfin_write32(EMAC_TXC_ABORT, val)
+#define bfin_read_EMAC_PTP_CTL() bfin_read16(EMAC_PTP_CTL)
+#define bfin_write_EMAC_PTP_CTL(val) bfin_write16(EMAC_PTP_CTL, val)
+#define bfin_read_EMAC_PTP_IE() bfin_read16(EMAC_PTP_IE)
+#define bfin_write_EMAC_PTP_IE(val) bfin_write16(EMAC_PTP_IE, val)
+#define bfin_read_EMAC_PTP_ISTAT() bfin_read16(EMAC_PTP_ISTAT)
+#define bfin_write_EMAC_PTP_ISTAT(val) bfin_write16(EMAC_PTP_ISTAT, val)
+#define bfin_read_EMAC_PTP_FOFF() bfin_read32(EMAC_PTP_FOFF)
+#define bfin_write_EMAC_PTP_FOFF(val) bfin_write32(EMAC_PTP_FOFF, val)
+#define bfin_read_EMAC_PTP_FV1() bfin_read32(EMAC_PTP_FV1)
+#define bfin_write_EMAC_PTP_FV1(val) bfin_write32(EMAC_PTP_FV1, val)
+#define bfin_read_EMAC_PTP_FV2() bfin_read32(EMAC_PTP_FV2)
+#define bfin_write_EMAC_PTP_FV2(val) bfin_write32(EMAC_PTP_FV2, val)
+#define bfin_read_EMAC_PTP_FV3() bfin_read32(EMAC_PTP_FV3)
+#define bfin_write_EMAC_PTP_FV3(val) bfin_write32(EMAC_PTP_FV3, val)
+#define bfin_read_EMAC_PTP_ADDEND() bfin_read32(EMAC_PTP_ADDEND)
+#define bfin_write_EMAC_PTP_ADDEND(val) bfin_write32(EMAC_PTP_ADDEND, val)
+#define bfin_read_EMAC_PTP_ACCR() bfin_read32(EMAC_PTP_ACCR)
+#define bfin_write_EMAC_PTP_ACCR(val) bfin_write32(EMAC_PTP_ACCR, val)
+#define bfin_read_EMAC_PTP_OFFSET() bfin_read32(EMAC_PTP_OFFSET)
+#define bfin_write_EMAC_PTP_OFFSET(val) bfin_write32(EMAC_PTP_OFFSET, val)
+#define bfin_read_EMAC_PTP_TIMELO() bfin_read32(EMAC_PTP_TIMELO)
+#define bfin_write_EMAC_PTP_TIMELO(val) bfin_write32(EMAC_PTP_TIMELO, val)
+#define bfin_read_EMAC_PTP_TIMEHI() bfin_read32(EMAC_PTP_TIMEHI)
+#define bfin_write_EMAC_PTP_TIMEHI(val) bfin_write32(EMAC_PTP_TIMEHI, val)
+#define bfin_read_EMAC_PTP_RXSNAPLO() bfin_read32(EMAC_PTP_RXSNAPLO)
+#define bfin_read_EMAC_PTP_RXSNAPHI() bfin_read32(EMAC_PTP_RXSNAPHI)
+#define bfin_read_EMAC_PTP_TXSNAPLO() bfin_read32(EMAC_PTP_TXSNAPLO)
+#define bfin_read_EMAC_PTP_TXSNAPHI() bfin_read32(EMAC_PTP_TXSNAPHI)
+#define bfin_read_EMAC_PTP_ALARMLO() bfin_read32(EMAC_PTP_ALARMLO)
+#define bfin_write_EMAC_PTP_ALARMLO(val) bfin_write32(EMAC_PTP_ALARMLO, val)
+#define bfin_read_EMAC_PTP_ALARMHI() bfin_read32(EMAC_PTP_ALARMHI)
+#define bfin_write_EMAC_PTP_ALARMHI(val) bfin_write32(EMAC_PTP_ALARMHI, val)
+#define bfin_read_EMAC_PTP_ID_OFF() bfin_read16(EMAC_PTP_ID_OFF)
+#define bfin_write_EMAC_PTP_ID_OFF(val) bfin_write16(EMAC_PTP_ID_OFF, val)
+#define bfin_read_EMAC_PTP_ID_SNAP() bfin_read32(EMAC_PTP_ID_SNAP)
+#define bfin_write_EMAC_PTP_ID_SNAP(val) bfin_write32(EMAC_PTP_ID_SNAP, val)
+#define bfin_read_EMAC_PTP_PPS_STARTHI() bfin_read32(EMAC_PTP_PPS_STARTHI)
+#define bfin_write_EMAC_PTP_PPS_STARTHI(val) bfin_write32(EMAC_PTP_PPS_STARTHI, val)
+#define bfin_read_EMAC_PTP_PPS_PERIOD() bfin_read32(EMAC_PTP_PPS_PERIOD)
+#define bfin_write_EMAC_PTP_PPS_PERIOD(val) bfin_write32(EMAC_PTP_PPS_PERIOD, val)
+
/* Removable Storage Interface Registers */
#define bfin_read_RSI_PWR_CTL() bfin_read16(RSI_PWR_CONTROL)
diff --git a/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h b/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h
index ee3d4733369c..1d970df7aee9 100644
--- a/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h
+++ b/arch/blackfin/mach-bf518/include/mach/cdefBF51x_base.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/cdefBF51x_base.h
- * Based on:
- * Author:
+ * Copyright 2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _CDEF_BF52X_H
diff --git a/arch/blackfin/mach-bf518/include/mach/defBF512.h b/arch/blackfin/mach-bf518/include/mach/defBF512.h
index a96ca90154dd..9b505bb0cb2d 100644
--- a/arch/blackfin/mach-bf518/include/mach/defBF512.h
+++ b/arch/blackfin/mach-bf518/include/mach/defBF512.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/defBF512.h
- * Based on:
- * Author:
+ * Copyright 2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF512_H
diff --git a/arch/blackfin/mach-bf518/include/mach/defBF514.h b/arch/blackfin/mach-bf518/include/mach/defBF514.h
index 56ee5a7c2007..b5adca23a788 100644
--- a/arch/blackfin/mach-bf518/include/mach/defBF514.h
+++ b/arch/blackfin/mach-bf518/include/mach/defBF514.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/defBF514.h
- * Based on:
- * Author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF514_H
diff --git a/arch/blackfin/mach-bf518/include/mach/defBF516.h b/arch/blackfin/mach-bf518/include/mach/defBF516.h
index dfc93843517d..7eb18774d727 100644
--- a/arch/blackfin/mach-bf518/include/mach/defBF516.h
+++ b/arch/blackfin/mach-bf518/include/mach/defBF516.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/defBF516.h
- * Based on:
- * Author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF516_H
diff --git a/arch/blackfin/mach-bf518/include/mach/defBF518.h b/arch/blackfin/mach-bf518/include/mach/defBF518.h
index 6e982abf4ede..794cf06eb5ba 100644
--- a/arch/blackfin/mach-bf518/include/mach/defBF518.h
+++ b/arch/blackfin/mach-bf518/include/mach/defBF518.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/defBF518.h
- * Based on:
- * Author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF518_H
@@ -648,4 +624,32 @@
#define RWR 0x1 /* Read Wait Request */
+/* Bit masks for EMAC_PTP_CTL */
+
+#define PTP_EN 0x1 /* Enable the PTP_TSYNC module */
+#define TL 0x2 /* Timestamp lock control */
+#define ASEN 0x10 /* Auxiliary snapshot control */
+#define PPSEN 0x80 /* Pulse-per-second (PPS) control */
+#define CKOEN 0x2000 /* Clock output control */
+
+/* Bit masks for EMAC_PTP_IE */
+
+#define ALIE 0x1 /* Alarm interrupt enable */
+#define RXEIE 0x2 /* Receive event interrupt enable */
+#define RXGIE 0x4 /* Receive general interrupt enable */
+#define TXIE 0x8 /* Transmit interrupt enable */
+#define RXOVE 0x10 /* Receive overrun error interrupt enable */
+#define TXOVE 0x20 /* Transmit overrun error interrupt enable */
+#define ASIE 0x40 /* Auxiliary snapshot interrupt enable */
+
+/* Bit masks for EMAC_PTP_ISTAT */
+
+#define ALS 0x1 /* Alarm status */
+#define RXEL 0x2 /* Receive event interrupt status */
+#define RXGL 0x4 /* Receive general interrupt status */
+#define TXTL 0x8 /* Transmit snapshot status */
+#define RXOV 0x10 /* Receive snapshot overrun status */
+#define TXOV 0x20 /* Transmit snapshot overrun status */
+#define ASL 0x40 /* Auxiliary snapshot interrupt status */
+
#endif /* _DEF_BF518_H */
diff --git a/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h b/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h
index 1bec8d1c2a73..e06f4112c695 100644
--- a/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h
+++ b/arch/blackfin/mach-bf518/include/mach/defBF51x_base.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf518/defBF51x_base.h
- * Based on:
- * Author:
+ * Copyright 2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF51X_H
diff --git a/arch/blackfin/mach-bf518/include/mach/gpio.h b/arch/blackfin/mach-bf518/include/mach/gpio.h
index 9757683c3948..bbab2d76499c 100644
--- a/arch/blackfin/mach-bf518/include/mach/gpio.h
+++ b/arch/blackfin/mach-bf518/include/mach/gpio.h
@@ -1,7 +1,4 @@
/*
- * File: arch/blackfin/mach-bf518/include/mach/gpio.h
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
* Copyright (C) 2008 Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/mach-bf518/include/mach/irq.h b/arch/blackfin/mach-bf518/include/mach/irq.h
index 3ff0f093313d..14e52ec7afa5 100644
--- a/arch/blackfin/mach-bf518/include/mach/irq.h
+++ b/arch/blackfin/mach-bf518/include/mach/irq.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf518/irq.h
- * based on: include/asm-blackfin/mach-bf527/irq.h
- * author: Michael Hennerich (michael.hennerich@analog.com)
+ * Copyright 2008 Analog Devices Inc.
*
- * created:
- * description:
- * system mmr register map
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later
*/
#ifndef _BF518_IRQ_H_
diff --git a/arch/blackfin/mach-bf518/include/mach/portmux.h b/arch/blackfin/mach-bf518/include/mach/portmux.h
index a0fc77fd3315..e352910f7f99 100644
--- a/arch/blackfin/mach-bf518/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf518/include/mach/portmux.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2008-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
#ifndef _MACH_PORTMUX_H_
#define _MACH_PORTMUX_H_
diff --git a/arch/blackfin/mach-bf518/ints-priority.c b/arch/blackfin/mach-bf518/ints-priority.c
index 3151fd5501ca..bb05bef34ec0 100644
--- a/arch/blackfin/mach-bf518/ints-priority.c
+++ b/arch/blackfin/mach-bf518/ints-priority.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-bf518/ints-priority.c
- * Based on: arch/blackfin/mach-bf527/ints-priority.c
- * Author: Bryan Wu <cooloney@kernel.org>
+ * Set up the interrupt priorities
*
- * Created:
- * Description: Set up the interrupt priorities
+ * Copyright 2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
diff --git a/arch/blackfin/mach-bf527/boards/cm_bf527.c b/arch/blackfin/mach-bf527/boards/cm_bf527.c
index 08a3f01c9886..f1996b13a3da 100644
--- a/arch/blackfin/mach-bf527/boards/cm_bf527.c
+++ b/arch/blackfin/mach-bf527/boards/cm_bf527.c
@@ -1,31 +1,10 @@
/*
- * File: arch/blackfin/mach-bf527/boards/cm-bf527.c
- * Based on: arch/blackfin/mach-bf537/boards/stamp.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2008-2009 Bluetechnix
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -616,12 +595,6 @@ static struct platform_device bfin_spi0_device = {
};
#endif /* spi master and devices */
-#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
-static struct platform_device bfin_fb_adv7393_device = {
- .name = "bfin-adv7393",
-};
-#endif
-
#if defined(CONFIG_MTD_GPIO_ADDR) || defined(CONFIG_MTD_GPIO_ADDR_MODULE)
static struct mtd_partition cm_partitions[] = {
{
@@ -786,6 +759,11 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
.irq = IRQ_PF8,
},
#endif
+#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
+ {
+ I2C_BOARD_INFO("bfin-adv7393", 0x2B),
+ },
+#endif
};
#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
@@ -821,19 +799,6 @@ static struct platform_device bfin_device_gpiokeys = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
static const unsigned int cclk_vlev_datasheet[] =
{
VRPAIR(VLEV_100, 400000000),
@@ -909,10 +874,6 @@ static struct platform_device *cmbf527_devices[] __initdata = {
&bfin_spi0_device,
#endif
-#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
- &bfin_fb_adv7393_device,
-#endif
-
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
&bfin_uart_device,
#endif
@@ -942,8 +903,6 @@ static struct platform_device *cmbf527_devices[] __initdata = {
#if defined(CONFIG_MTD_GPIO_ADDR) || defined(CONFIG_MTD_GPIO_ADDR_MODULE)
&cm_flash_device,
#endif
-
- &bfin_gpios_device,
};
static int __init cm_init(void)
diff --git a/arch/blackfin/mach-bf527/boards/ezbrd.c b/arch/blackfin/mach-bf527/boards/ezbrd.c
index 68b4c804364c..cad23b15d83c 100644
--- a/arch/blackfin/mach-bf527/boards/ezbrd.c
+++ b/arch/blackfin/mach-bf527/boards/ezbrd.c
@@ -1,31 +1,9 @@
/*
- * File: arch/blackfin/mach-bf527/boards/ezbrd.c
- * Based on: arch/blackfin/mach-bf537/boards/stamp.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -611,19 +589,6 @@ static struct platform_device bfin_device_gpiokeys = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
static const unsigned int cclk_vlev_datasheet[] =
{
VRPAIR(VLEV_100, 400000000),
@@ -732,8 +697,6 @@ static struct platform_device *stamp_devices[] __initdata = {
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
&ezbrd_flash_device,
#endif
-
- &bfin_gpios_device,
};
static int __init ezbrd_init(void)
diff --git a/arch/blackfin/mach-bf527/boards/ezkit.c b/arch/blackfin/mach-bf527/boards/ezkit.c
index 2849b09abe99..f09665f74ba0 100644
--- a/arch/blackfin/mach-bf527/boards/ezkit.c
+++ b/arch/blackfin/mach-bf527/boards/ezkit.c
@@ -1,31 +1,9 @@
/*
- * File: arch/blackfin/mach-bf527/boards/ezkit.c
- * Based on: arch/blackfin/mach-bf537/boards/stamp.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -716,12 +694,6 @@ static struct platform_device bfin_fb_device = {
};
#endif
-#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
-static struct platform_device bfin_fb_adv7393_device = {
- .name = "bfin-adv7393",
-};
-#endif
-
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
static struct resource bfin_uart_resources[] = {
#ifdef CONFIG_SERIAL_BFIN_UART0
@@ -837,6 +809,11 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
.irq = IRQ_PF8,
},
#endif
+#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
+ {
+ I2C_BOARD_INFO("bfin-adv7393", 0x2B),
+ },
+#endif
};
#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
@@ -905,19 +882,6 @@ static struct platform_device bfin_rotary_device = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
static const unsigned int cclk_vlev_datasheet[] =
{
VRPAIR(VLEV_100, 400000000),
@@ -1001,10 +965,6 @@ static struct platform_device *stamp_devices[] __initdata = {
&bf52x_t350mcqb_device,
#endif
-#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
- &bfin_fb_adv7393_device,
-#endif
-
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
&bfin_uart_device,
#endif
@@ -1038,8 +998,6 @@ static struct platform_device *stamp_devices[] __initdata = {
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
&ezkit_flash_device,
#endif
-
- &bfin_gpios_device,
};
static int __init ezkit_init(void)
diff --git a/arch/blackfin/mach-bf527/dma.c b/arch/blackfin/mach-bf527/dma.c
index 231877578243..7bc7577d6c4f 100644
--- a/arch/blackfin/mach-bf527/dma.c
+++ b/arch/blackfin/mach-bf527/dma.c
@@ -1,31 +1,11 @@
/*
- * File: arch/blackfin/mach-bf527/dma.c
- * Based on:
- * Author:
+ * This file contains the simple DMA Implementation for Blackfin
*
- * Created:
- * Description: This file contains the simple DMA Implementation for Blackfin
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
+
#include <linux/module.h>
#include <asm/blackfin.h>
diff --git a/arch/blackfin/mach-bf527/include/mach/bf527.h b/arch/blackfin/mach-bf527/include/mach/bf527.h
index 3832aab11e9a..ff68c8897087 100644
--- a/arch/blackfin/mach-bf527/include/mach/bf527.h
+++ b/arch/blackfin/mach-bf527/include/mach/bf527.h
@@ -1,30 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf527/bf527.h
- * Based on: include/asm-blackfin/mach-bf537/bf537.h
- * Author: Michael Hennerich (michael.hennerich@analog.com)
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Created:
- * Description: SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF527
- *
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __MACH_BF527_H__
diff --git a/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
index ebd6cebc1fbc..c1d55b878b45 100644
--- a/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf527/include/mach/bfin_serial_5xx.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf527/bfin_serial_5xx.h
- * based on:
- * author:
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * created:
- * description:
- * blackfin serial driver head file
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later
*/
#include <linux/serial.h>
diff --git a/arch/blackfin/mach-bf527/include/mach/blackfin.h b/arch/blackfin/mach-bf527/include/mach/blackfin.h
index ea9cb0fef8bc..e7d6034f268f 100644
--- a/arch/blackfin/mach-bf527/include/mach/blackfin.h
+++ b/arch/blackfin/mach-bf527/include/mach/blackfin.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf527/blackfin.h
- * Based on:
- * Author:
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _MACH_BLACKFIN_H_
diff --git a/arch/blackfin/mach-bf527/include/mach/cdefBF522.h b/arch/blackfin/mach-bf527/include/mach/cdefBF522.h
index 663c2bbdfd91..1079af8c7aef 100644
--- a/arch/blackfin/mach-bf527/include/mach/cdefBF522.h
+++ b/arch/blackfin/mach-bf527/include/mach/cdefBF522.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf527/cdefbf522.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description: system mmr register map
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _CDEF_BF522_H
diff --git a/arch/blackfin/mach-bf527/include/mach/cdefBF525.h b/arch/blackfin/mach-bf527/include/mach/cdefBF525.h
index 00377eb59b75..dc3119e9f663 100644
--- a/arch/blackfin/mach-bf527/include/mach/cdefBF525.h
+++ b/arch/blackfin/mach-bf527/include/mach/cdefBF525.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf527/cdefbf525.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description: system mmr register map
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _CDEF_BF525_H
diff --git a/arch/blackfin/mach-bf527/include/mach/cdefBF527.h b/arch/blackfin/mach-bf527/include/mach/cdefBF527.h
index fca8db708119..d6579449ee46 100644
--- a/arch/blackfin/mach-bf527/include/mach/cdefBF527.h
+++ b/arch/blackfin/mach-bf527/include/mach/cdefBF527.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf527/cdefbf527.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description: system mmr register map
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _CDEF_BF527_H
diff --git a/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h b/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h
index 1fe76d8e0403..7014dde10dd6 100644
--- a/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h
+++ b/arch/blackfin/mach-bf527/include/mach/cdefBF52x_base.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf527/cdefBF52x_base.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _CDEF_BF52X_H
diff --git a/arch/blackfin/mach-bf527/include/mach/defBF522.h b/arch/blackfin/mach-bf527/include/mach/defBF522.h
index 0a8cdcdf0b49..cb139a254810 100644
--- a/arch/blackfin/mach-bf527/include/mach/defBF522.h
+++ b/arch/blackfin/mach-bf527/include/mach/defBF522.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf527/defBF522.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF522_H
diff --git a/arch/blackfin/mach-bf527/include/mach/defBF525.h b/arch/blackfin/mach-bf527/include/mach/defBF525.h
index 5cd7576fef76..82abefc1ef6c 100644
--- a/arch/blackfin/mach-bf527/include/mach/defBF525.h
+++ b/arch/blackfin/mach-bf527/include/mach/defBF525.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf527/defBF525.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF525_H
diff --git a/arch/blackfin/mach-bf527/include/mach/defBF527.h b/arch/blackfin/mach-bf527/include/mach/defBF527.h
index f040f364afa3..570a125df025 100644
--- a/arch/blackfin/mach-bf527/include/mach/defBF527.h
+++ b/arch/blackfin/mach-bf527/include/mach/defBF527.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf527/defBF527.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF527_H
diff --git a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
index 68b55d03fedf..f821700716ee 100644
--- a/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
+++ b/arch/blackfin/mach-bf527/include/mach/defBF52x_base.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf527/defBF52x_base.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF52X_H
diff --git a/arch/blackfin/mach-bf527/include/mach/gpio.h b/arch/blackfin/mach-bf527/include/mach/gpio.h
index 06b6eebf0d49..104bff85290d 100644
--- a/arch/blackfin/mach-bf527/include/mach/gpio.h
+++ b/arch/blackfin/mach-bf527/include/mach/gpio.h
@@ -1,7 +1,4 @@
/*
- * File: arch/blackfin/mach-bf527/include/mach/gpio.h
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
* Copyright (C) 2008 Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/mach-bf527/include/mach/irq.h b/arch/blackfin/mach-bf527/include/mach/irq.h
index 8ea660d8151f..aa6579a64a2f 100644
--- a/arch/blackfin/mach-bf527/include/mach/irq.h
+++ b/arch/blackfin/mach-bf527/include/mach/irq.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf527/irq.h
- * based on: include/asm-blackfin/mach-bf537/irq.h
- * author: Michael Hennerich (michael.hennerich@analog.com)
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * created:
- * description:
- * system mmr register map
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later
*/
#ifndef _BF527_IRQ_H_
diff --git a/arch/blackfin/mach-bf527/include/mach/portmux.h b/arch/blackfin/mach-bf527/include/mach/portmux.h
index 72b1652be4da..d4518b6f4adf 100644
--- a/arch/blackfin/mach-bf527/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf527/include/mach/portmux.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2007-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
#ifndef _MACH_PORTMUX_H_
#define _MACH_PORTMUX_H_
diff --git a/arch/blackfin/mach-bf527/ints-priority.c b/arch/blackfin/mach-bf527/ints-priority.c
index f8c8acd73e30..44ca215bf164 100644
--- a/arch/blackfin/mach-bf527/ints-priority.c
+++ b/arch/blackfin/mach-bf527/ints-priority.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-bf537/ints-priority.c
- * Based on: arch/blackfin/mach-bf533/ints-priority.c
- * Author: Michael Hennerich (michael.hennerich@analog.com)
+ * Set up the interrupt priorities
*
- * Created:
- * Description: Set up the interrupt priorities
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
diff --git a/arch/blackfin/mach-bf533/boards/H8606.c b/arch/blackfin/mach-bf533/boards/H8606.c
index 6c2b47fe4fe4..43f43a095a99 100644
--- a/arch/blackfin/mach-bf533/boards/H8606.c
+++ b/arch/blackfin/mach-bf533/boards/H8606.c
@@ -1,32 +1,11 @@
/*
- * File: arch/blackfin/mach-bf533/H8606.c
- * Based on: arch/blackfin/mach-bf533/stamp.c
- * Author: Javier Herrero <jherrero@hvsistemas.es>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2007-2008 HV Sistemas S.L.
+ * Javier Herrero <jherrero@hvsistemas.es>
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created: 2007
- * Description: Board Info File for the HV Sistemas H8606 board
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2006 Analog Devices Inc
- * Copyright 2007,2008 HV Sistemas S.L.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
diff --git a/arch/blackfin/mach-bf533/boards/blackstamp.c b/arch/blackfin/mach-bf533/boards/blackstamp.c
index 8208d67e2c97..b580884848d4 100644
--- a/arch/blackfin/mach-bf533/boards/blackstamp.c
+++ b/arch/blackfin/mach-bf533/boards/blackstamp.c
@@ -1,16 +1,10 @@
/*
- * File: arch/blackfin/mach-bf533/blackstamp.c
- * Based on: arch/blackfin/mach-bf533/stamp.c
- * Author: Benjamin Matthews <bmat@lle.rochester.edu>
- * Aidan Williams <aidan@nicta.com.au>
+ * Board Info File for the BlackStamp
*
- * Created: 2008
- * Description: Board Info File for the BlackStamp
- *
- * Copyright 2005 National ICT Australia (NICTA)
* Copyright 2004-2008 Analog Devices Inc.
- *
- * Enter bugs at http://blackfin.uclinux.org/
+ * 2008 Benjamin Matthews <bmat@lle.rochester.edu>
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
* More info about the BlackStamp at:
* http://blackfin.uclinux.org/gf/project/blackstamp/
@@ -281,19 +275,6 @@ static struct platform_device bfin_device_gpiokeys = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
#include <linux/i2c-gpio.h>
@@ -384,8 +365,6 @@ static struct platform_device *stamp_devices[] __initdata = {
#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
&i2c_gpio_device,
#endif
-
- &bfin_gpios_device,
};
static int __init blackstamp_init(void)
diff --git a/arch/blackfin/mach-bf533/boards/cm_bf533.c b/arch/blackfin/mach-bf533/boards/cm_bf533.c
index 7443b26c80c5..7fc3b860d4ae 100644
--- a/arch/blackfin/mach-bf533/boards/cm_bf533.c
+++ b/arch/blackfin/mach-bf533/boards/cm_bf533.c
@@ -1,30 +1,10 @@
/*
- * File: arch/blackfin/mach-bf533/boards/cm_bf533.c
- * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
- * Author: Aidan Williams <aidan@nicta.com.au> Copyright 2005
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2008-2009 Bluetechnix
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created: 2005
- * Description: Board description file
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -261,19 +241,6 @@ static struct platform_device smsc911x_device = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
static struct resource bfin_uart_resources[] = {
{
@@ -506,8 +473,6 @@ static struct platform_device *cm_bf533_devices[] __initdata = {
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
&para_flash_device,
#endif
-
- &bfin_gpios_device,
};
static int __init cm_bf533_init(void)
diff --git a/arch/blackfin/mach-bf533/boards/ezkit.c b/arch/blackfin/mach-bf533/boards/ezkit.c
index fd518e383b79..d4689dcc198e 100644
--- a/arch/blackfin/mach-bf533/boards/ezkit.c
+++ b/arch/blackfin/mach-bf533/boards/ezkit.c
@@ -1,31 +1,9 @@
/*
- * File: arch/blackfin/mach-bf533/ezkit.c
- * Based on: Original Work
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created: 2005
- * Description:
- *
- * Modified: Robin Getz <rgetz@blackfin.uclinux.org> - Named the boards
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -33,12 +11,14 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/plat-ram.h>
+#include <linux/mtd/physmap.h>
#include <linux/spi/spi.h>
#include <linux/spi/flash.h>
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
#include <linux/usb/isp1362.h>
#endif
#include <linux/irq.h>
+#include <linux/i2c.h>
#include <asm/dma.h>
#include <asm/bfin5xx_spi.h>
#include <asm/portmux.h>
@@ -56,12 +36,6 @@ static struct platform_device rtc_device = {
};
#endif
-#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
-static struct platform_device bfin_fb_adv7393_device = {
- .name = "bfin-adv7393",
-};
-#endif
-
/*
* USB-LAN EzExtender board
* Driver needs to know address, irq and flag pin.
@@ -98,54 +72,69 @@ static struct platform_device smc91x_device = {
};
#endif
-#if defined(CONFIG_MTD_PSD4256G) || defined(CONFIG_MTD_PSD4256G_MODULE)
-static const char *map_probes[] = {
- "stm_flash",
- NULL,
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+static struct mtd_partition ezkit_partitions_a[] = {
+ {
+ .name = "bootloader(nor a)",
+ .size = 0x40000,
+ .offset = 0,
+ }, {
+ .name = "linux kernel(nor a)",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ },
};
-static struct platdata_mtd_ram stm_pri_data_a = {
- .mapname = "Flash A Primary",
- .map_probes = map_probes,
- .bankwidth = 2,
+static struct physmap_flash_data ezkit_flash_data_a = {
+ .width = 2,
+ .parts = ezkit_partitions_a,
+ .nr_parts = ARRAY_SIZE(ezkit_partitions_a),
};
-static struct resource stm_pri_resource_a = {
+static struct resource ezkit_flash_resource_a = {
.start = 0x20000000,
.end = 0x200fffff,
.flags = IORESOURCE_MEM,
};
-static struct platform_device stm_pri_device_a = {
- .name = "mtd-ram",
+static struct platform_device ezkit_flash_device_a = {
+ .name = "physmap-flash",
.id = 0,
.dev = {
- .platform_data = &stm_pri_data_a,
+ .platform_data = &ezkit_flash_data_a,
},
.num_resources = 1,
- .resource = &stm_pri_resource_a,
+ .resource = &ezkit_flash_resource_a,
+};
+
+static struct mtd_partition ezkit_partitions_b[] = {
+ {
+ .name = "file system(nor b)",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ },
};
-static struct platdata_mtd_ram stm_pri_data_b = {
- .mapname = "Flash B Primary",
- .map_probes = map_probes,
- .bankwidth = 2,
+static struct physmap_flash_data ezkit_flash_data_b = {
+ .width = 2,
+ .parts = ezkit_partitions_b,
+ .nr_parts = ARRAY_SIZE(ezkit_partitions_b),
};
-static struct resource stm_pri_resource_b = {
+static struct resource ezkit_flash_resource_b = {
.start = 0x20100000,
.end = 0x201fffff,
.flags = IORESOURCE_MEM,
};
-static struct platform_device stm_pri_device_b = {
- .name = "mtd-ram",
+static struct platform_device ezkit_flash_device_b = {
+ .name = "physmap-flash",
.id = 4,
.dev = {
- .platform_data = &stm_pri_data_b,
+ .platform_data = &ezkit_flash_data_b,
},
.num_resources = 1,
- .resource = &stm_pri_resource_b,
+ .resource = &ezkit_flash_resource_b,
};
#endif
@@ -400,19 +389,6 @@ static struct platform_device bfin_device_gpiokeys = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
#include <linux/i2c-gpio.h>
@@ -460,13 +436,21 @@ static struct platform_device bfin_dpmc = {
},
};
+static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
+#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
+ {
+ I2C_BOARD_INFO("bfin-adv7393", 0x2B),
+ },
+#endif
+};
+
static struct platform_device *ezkit_devices[] __initdata = {
&bfin_dpmc,
-#if defined(CONFIG_MTD_PSD4256G) || defined(CONFIG_MTD_PSD4256G_MODULE)
- &stm_pri_device_a,
- &stm_pri_device_b,
+#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
+ &ezkit_flash_device_a,
+ &ezkit_flash_device_b,
#endif
#if defined(CONFIG_MTD_PLATRAM) || defined(CONFIG_MTD_PLATRAM_MODULE)
@@ -482,10 +466,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
&bfin_spi0_device,
#endif
-#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
- &bfin_fb_adv7393_device,
-#endif
-
#if defined(CONFIG_RTC_DRV_BFIN) || defined(CONFIG_RTC_DRV_BFIN_MODULE)
&rtc_device,
#endif
@@ -507,8 +487,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
&i2c_gpio_device,
#endif
-
- &bfin_gpios_device,
};
static int __init ezkit_init(void)
@@ -516,6 +494,8 @@ static int __init ezkit_init(void)
printk(KERN_INFO "%s(): registering device resources\n", __func__);
platform_add_devices(ezkit_devices, ARRAY_SIZE(ezkit_devices));
spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
+ i2c_register_board_info(0, bfin_i2c_board_info,
+ ARRAY_SIZE(bfin_i2c_board_info));
return 0;
}
diff --git a/arch/blackfin/mach-bf533/boards/ip0x.c b/arch/blackfin/mach-bf533/boards/ip0x.c
index f19b63378b12..644be5e5ab6f 100644
--- a/arch/blackfin/mach-bf533/boards/ip0x.c
+++ b/arch/blackfin/mach-bf533/boards/ip0x.c
@@ -1,34 +1,12 @@
/*
- * File: arch/blackfin/mach-bf533/ip0x.c
- * Based on: arch/blackfin/mach-bf533/bf1.c
- * Based on: arch/blackfin/mach-bf533/stamp.c
- * Author: Ivan Danov <idanov@gmail.com>
- * Modified for IP0X David Rowe
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2007 David Rowe
+ * 2006 Intratrade Ltd.
+ * Ivan Danov <idanov@gmail.com>
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created: 2007
- * Description: Board info file for the IP04/IP08 boards, which
- * are derived from the BlackfinOne V2.0 boards.
- *
- * Modified:
- * COpyright 2007 David Rowe
- * Copyright 2006 Intratrade Ltd.
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -145,7 +123,6 @@ static struct bfin5xx_spi_chip mmc_spi_chip_info = {
.ctl_reg = 0x1000, /* CPOL=0,CPHA=0,Sandisk 1G work */
.enable_dma = 0, /* if 1 - block!!! */
.bits_per_word = 8,
- .cs_change_per_word = 0,
};
#endif
diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
index 729fd7c26336..82f70efd66e7 100644
--- a/arch/blackfin/mach-bf533/boards/stamp.c
+++ b/arch/blackfin/mach-bf533/boards/stamp.c
@@ -1,31 +1,9 @@
/*
- * File: arch/blackfin/mach-bf533/stamp.c
- * Based on: arch/blackfin/mach-bf533/ezkit.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created: 2005
- * Description: Board Info File for the BF533-STAMP
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -95,12 +73,6 @@ static struct platform_device smc91x_device = {
};
#endif
-#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
-static struct platform_device bfin_fb_adv7393_device = {
- .name = "bfin-adv7393",
-};
-#endif
-
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
static struct resource net2272_bfin_resources[] = {
{
@@ -436,19 +408,6 @@ static struct platform_device bfin_device_gpiokeys = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
#include <linux/i2c-gpio.h>
@@ -487,6 +446,11 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
.irq = 39,
},
#endif
+#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
+ {
+ I2C_BOARD_INFO("bfin-adv7393", 0x2B),
+ },
+#endif
};
static const unsigned int cclk_vlev_datasheet[] =
@@ -528,10 +492,6 @@ static struct platform_device *stamp_devices[] __initdata = {
&smc91x_device,
#endif
-#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
- &bfin_fb_adv7393_device,
-#endif
-
#if defined(CONFIG_USB_NET2272) || defined(CONFIG_USB_NET2272_MODULE)
&net2272_bfin_device,
#endif
@@ -563,8 +523,6 @@ static struct platform_device *stamp_devices[] __initdata = {
&i2c_gpio_device,
#endif
- &bfin_gpios_device,
-
#if defined(CONFIG_MTD_BFIN_ASYNC) || defined(CONFIG_MTD_BFIN_ASYNC_MODULE)
&stamp_flash_device,
#endif
diff --git a/arch/blackfin/mach-bf533/dma.c b/arch/blackfin/mach-bf533/dma.c
index 7a443c37fb9f..4a14a46a9a68 100644
--- a/arch/blackfin/mach-bf533/dma.c
+++ b/arch/blackfin/mach-bf533/dma.c
@@ -1,31 +1,11 @@
/*
- * File: arch/blackfin/mach-bf533/dma.c
- * Based on:
- * Author:
+ * simple DMA Implementation for Blackfin
*
- * Created:
- * Description: This file contains the simple DMA Implementation for Blackfin
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
+
#include <linux/module.h>
#include <asm/blackfin.h>
diff --git a/arch/blackfin/mach-bf533/include/mach/bf533.h b/arch/blackfin/mach-bf533/include/mach/bf533.h
index cf4427cd3f72..e3e05f8f7af9 100644
--- a/arch/blackfin/mach-bf533/include/mach/bf533.h
+++ b/arch/blackfin/mach-bf533/include/mach/bf533.h
@@ -1,30 +1,9 @@
/*
- * File: include/asm-blackfin/mach-bf533/bf533.h
- * Based on:
- * Author:
+ * SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
*
- * Created:
- * Description: SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __MACH_BF533_H__
diff --git a/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
index 6965b4088c44..9e1f3defb6bc 100644
--- a/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf533/include/mach/bfin_serial_5xx.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf533/bfin_serial_5xx.h
- * based on:
- * author:
+ * Copyright 2006-2009 Analog Devices Inc.
*
- * created:
- * description:
- * blackfin serial driver head file
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later
*/
#include <linux/serial.h>
diff --git a/arch/blackfin/mach-bf533/include/mach/blackfin.h b/arch/blackfin/mach-bf533/include/mach/blackfin.h
index 499e897a4f4f..f4bd6df5d968 100644
--- a/arch/blackfin/mach-bf533/include/mach/blackfin.h
+++ b/arch/blackfin/mach-bf533/include/mach/blackfin.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf533/blackfin.h
- * Based on:
- * Author:
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _MACH_BLACKFIN_H_
diff --git a/arch/blackfin/mach-bf533/include/mach/cdefBF532.h b/arch/blackfin/mach-bf533/include/mach/cdefBF532.h
index bbc3c8386d48..feb2392c43ea 100644
--- a/arch/blackfin/mach-bf533/include/mach/cdefBF532.h
+++ b/arch/blackfin/mach-bf533/include/mach/cdefBF532.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf533/cdefBF532.h
- * Based on:
- * Author:
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _CDEF_BF532_H
diff --git a/arch/blackfin/mach-bf533/include/mach/defBF532.h b/arch/blackfin/mach-bf533/include/mach/defBF532.h
index 7f4633223e6d..02b328eb0e07 100644
--- a/arch/blackfin/mach-bf533/include/mach/defBF532.h
+++ b/arch/blackfin/mach-bf533/include/mach/defBF532.h
@@ -1,48 +1,10 @@
-/************************************************************************
- *
- * This file is subject to the terms and conditions of the GNU Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Non-GPL License also available as part of VisualDSP++
- * http://www.analog.com/processors/resources/crosscore/visualDspDevSoftware.html
- *
- * (c) Copyright 2001-2005 Analog Devices, Inc. All rights reserved
- *
- * This file under source code control, please send bugs or changes to:
- * dsptools.support@analog.com
- *
- ************************************************************************/
/*
- * File: include/asm-blackfin/mach-bf533/defBF532.h
- * Based on:
- * Author:
- *
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
+ * System & MMR bit and Address definitions for ADSP-BF532
*
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
-/* SYSTEM & MM REGISTER BIT & ADDRESS DEFINITIONS FOR ADSP-BF532 */
#ifndef _DEF_BF532_H
#define _DEF_BF532_H
diff --git a/arch/blackfin/mach-bf533/include/mach/gpio.h b/arch/blackfin/mach-bf533/include/mach/gpio.h
index e45c17077aff..2af19d69a7a7 100644
--- a/arch/blackfin/mach-bf533/include/mach/gpio.h
+++ b/arch/blackfin/mach-bf533/include/mach/gpio.h
@@ -1,7 +1,4 @@
/*
- * File: arch/blackfin/mach-bf533/include/mach/gpio.h
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
* Copyright (C) 2008 Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/mach-bf533/include/mach/irq.h b/arch/blackfin/mach-bf533/include/mach/irq.h
index db1e346cd1aa..c31498be0bbb 100644
--- a/arch/blackfin/mach-bf533/include/mach/irq.h
+++ b/arch/blackfin/mach-bf533/include/mach/irq.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf533/defBF532.h
- * Based on:
- * Author:
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _BF533_IRQ_H_
diff --git a/arch/blackfin/mach-bf533/include/mach/portmux.h b/arch/blackfin/mach-bf533/include/mach/portmux.h
index 2f59ce0b0cb5..075dae1af164 100644
--- a/arch/blackfin/mach-bf533/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf533/include/mach/portmux.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2007-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
#ifndef _MACH_PORTMUX_H_
#define _MACH_PORTMUX_H_
diff --git a/arch/blackfin/mach-bf533/ints-priority.c b/arch/blackfin/mach-bf533/ints-priority.c
index f51994b7a2b9..8f714cf8135b 100644
--- a/arch/blackfin/mach-bf533/ints-priority.c
+++ b/arch/blackfin/mach-bf533/ints-priority.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-bf533/ints-priority.c
- * Based on:
- * Author: Michael Hennerich
+ * Set up the interrupt priorities
*
- * Created: ?
- * Description: Set up the interrupt priorities
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537e.c b/arch/blackfin/mach-bf537/boards/cm_bf537e.c
index 87acb7dd2df3..c85f4d770535 100644
--- a/arch/blackfin/mach-bf537/boards/cm_bf537e.c
+++ b/arch/blackfin/mach-bf537/boards/cm_bf537e.c
@@ -1,31 +1,10 @@
/*
- * File: arch/blackfin/mach-bf537/boards/cm_bf537.c
- * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2008-2009 Bluetechnix
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created: 2005
- * Description: Board description file
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -297,19 +276,6 @@ static struct platform_device net2272_bfin_device = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_MTD_GPIO_ADDR) || defined(CONFIG_MTD_GPIO_ADDR_MODULE)
static struct mtd_partition cm_partitions[] = {
{
@@ -699,8 +665,6 @@ static struct platform_device *cm_bf537e_devices[] __initdata = {
#if defined(CONFIG_MTD_GPIO_ADDR) || defined(CONFIG_MTD_GPIO_ADDR_MODULE)
&cm_flash_device,
#endif
-
- &bfin_gpios_device,
};
static int __init cm_bf537e_init(void)
diff --git a/arch/blackfin/mach-bf537/boards/cm_bf537u.c b/arch/blackfin/mach-bf537/boards/cm_bf537u.c
index 8219dc3d65bd..ea11aa81340d 100644
--- a/arch/blackfin/mach-bf537/boards/cm_bf537u.c
+++ b/arch/blackfin/mach-bf537/boards/cm_bf537u.c
@@ -1,31 +1,10 @@
/*
- * File: arch/blackfin/mach-bf537/boards/cm_bf537u.c
- * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2008-2009 Bluetechnix
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created: 2005
- * Description: Board description file
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -298,19 +277,6 @@ static struct platform_device net2272_bfin_device = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_MTD_GPIO_ADDR) || defined(CONFIG_MTD_GPIO_ADDR_MODULE)
static struct mtd_partition cm_partitions[] = {
{
@@ -605,8 +571,6 @@ static struct platform_device *cm_bf537u_devices[] __initdata = {
#if defined(CONFIG_MTD_GPIO_ADDR) || defined(CONFIG_MTD_GPIO_ADDR_MODULE)
&cm_flash_device,
#endif
-
- &bfin_gpios_device,
};
static int __init cm_bf537u_init(void)
diff --git a/arch/blackfin/mach-bf537/boards/minotaur.c b/arch/blackfin/mach-bf537/boards/minotaur.c
index 399f81da7b93..0da927252701 100644
--- a/arch/blackfin/mach-bf537/boards/minotaur.c
+++ b/arch/blackfin/mach-bf537/boards/minotaur.c
@@ -1,4 +1,10 @@
/*
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2008-2009 Cambridge Signal Processing
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
+ *
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
diff --git a/arch/blackfin/mach-bf537/boards/pnav10.c b/arch/blackfin/mach-bf537/boards/pnav10.c
index 10b35b838bac..9ba290466b56 100644
--- a/arch/blackfin/mach-bf537/boards/pnav10.c
+++ b/arch/blackfin/mach-bf537/boards/pnav10.c
@@ -1,31 +1,9 @@
/*
- * File: arch/blackfin/mach-bf537/boards/stamp.c
- * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -302,7 +280,6 @@ static struct bfin5xx_spi_chip mmc_spi_chip_info = {
#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
- .cs_change_per_word = 0,
.enable_dma = 0,
.bits_per_word = 16,
};
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 9db6b40743e0..c46baa5e6d9b 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -1,31 +1,9 @@
/*
- * File: arch/blackfin/mach-bf537/boards/stamp.c
- * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -121,19 +99,6 @@ static struct platform_device bfin_device_gpiokeys = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_BFIN_CFPCMCIA) || defined(CONFIG_BFIN_CFPCMCIA_MODULE)
static struct resource bfin_pcmcia_cf_resources[] = {
{
@@ -1078,12 +1043,6 @@ static struct platform_device bfin_fb_device = {
};
#endif
-#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
-static struct platform_device bfin_fb_adv7393_device = {
- .name = "bfin-adv7393",
-};
-#endif
-
#if defined(CONFIG_FB_BFIN_LQ035Q1) || defined(CONFIG_FB_BFIN_LQ035Q1_MODULE)
#include <asm/bfin-lq035q1.h>
@@ -1498,6 +1457,11 @@ static struct i2c_board_info __initdata bfin_i2c_board_info[] = {
.platform_data = (void *)&adp5588_gpio_data,
},
#endif
+#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
+ {
+ I2C_BOARD_INFO("bfin-adv7393", 0x2B),
+ },
+#endif
};
#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
@@ -1668,10 +1632,6 @@ static struct platform_device *stamp_devices[] __initdata = {
&bfin_lq035q1_device,
#endif
-#if defined(CONFIG_FB_BFIN_7393) || defined(CONFIG_FB_BFIN_7393_MODULE)
- &bfin_fb_adv7393_device,
-#endif
-
#if defined(CONFIG_SERIAL_BFIN) || defined(CONFIG_SERIAL_BFIN_MODULE)
&bfin_uart_device,
#endif
@@ -1702,8 +1662,6 @@ static struct platform_device *stamp_devices[] __initdata = {
&bfin_device_gpiokeys,
#endif
- &bfin_gpios_device,
-
#if defined(CONFIG_MTD_NAND_PLATFORM) || defined(CONFIG_MTD_NAND_PLATFORM_MODULE)
&bfin_async_nand_device,
#endif
diff --git a/arch/blackfin/mach-bf537/boards/tcm_bf537.c b/arch/blackfin/mach-bf537/boards/tcm_bf537.c
index 61353f7bcb9e..57163b65a4f5 100644
--- a/arch/blackfin/mach-bf537/boards/tcm_bf537.c
+++ b/arch/blackfin/mach-bf537/boards/tcm_bf537.c
@@ -1,31 +1,10 @@
/*
- * File: arch/blackfin/mach-bf537/boards/tcm_bf537.c
- * Based on: arch/blackfin/mach-bf533/boards/cm_bf537.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2008-2009 Bluetechnix
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created: 2005
- * Description: Board description file
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -298,19 +277,6 @@ static struct platform_device net2272_bfin_device = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_MTD_GPIO_ADDR) || defined(CONFIG_MTD_GPIO_ADDR_MODULE)
static struct mtd_partition cm_partitions[] = {
{
@@ -607,8 +573,6 @@ static struct platform_device *cm_bf537_devices[] __initdata = {
#if defined(CONFIG_MTD_GPIO_ADDR) || defined(CONFIG_MTD_GPIO_ADDR_MODULE)
&cm_flash_device,
#endif
-
- &bfin_gpios_device,
};
static int __init tcm_bf537_init(void)
diff --git a/arch/blackfin/mach-bf537/dma.c b/arch/blackfin/mach-bf537/dma.c
index d23fc0edf2b9..5c8c4ed517bb 100644
--- a/arch/blackfin/mach-bf537/dma.c
+++ b/arch/blackfin/mach-bf537/dma.c
@@ -1,31 +1,11 @@
/*
- * File: arch/blackfin/mach-bf537/dma.c
- * Based on:
- * Author:
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Created:
- * Description: This file contains the simple DMA Implementation for Blackfin
+ * Licensed under the GPL-2 or later.
*
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * This file contains the simple DMA Implementation for Blackfin
*/
+
#include <linux/module.h>
#include <asm/blackfin.h>
diff --git a/arch/blackfin/mach-bf537/include/mach/bf537.h b/arch/blackfin/mach-bf537/include/mach/bf537.h
index f194a848ae8e..17fab4474669 100644
--- a/arch/blackfin/mach-bf537/include/mach/bf537.h
+++ b/arch/blackfin/mach-bf537/include/mach/bf537.h
@@ -1,30 +1,9 @@
/*
- * File: include/asm-blackfin/mach-bf537/bf537.h
- * Based on:
- * Author:
+ * System MMR Register and memory map for ADSP-BF537
*
- * Created:
- * Description: SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF537
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __MACH_BF537_H__
diff --git a/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
index e95d54f9af6c..635c91c526a3 100644
--- a/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf537/include/mach/bfin_serial_5xx.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf537/bfin_serial_5xx.h
- * based on:
- * author:
+ * Copyright 2006-2009 Analog Devices Inc.
*
- * created:
- * description:
- * blackfin serial driver header files
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later
*/
#include <linux/serial.h>
diff --git a/arch/blackfin/mach-bf537/include/mach/blackfin.h b/arch/blackfin/mach-bf537/include/mach/blackfin.h
index 9ee8834c8f1a..eab006d260c5 100644
--- a/arch/blackfin/mach-bf537/include/mach/blackfin.h
+++ b/arch/blackfin/mach-bf537/include/mach/blackfin.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf537/blackfin.h
- * Based on:
- * Author:
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _MACH_BLACKFIN_H_
diff --git a/arch/blackfin/mach-bf537/include/mach/cdefBF534.h b/arch/blackfin/mach-bf537/include/mach/cdefBF534.h
index 5f8b5f845be6..91825c9bd226 100644
--- a/arch/blackfin/mach-bf537/include/mach/cdefBF534.h
+++ b/arch/blackfin/mach-bf537/include/mach/cdefBF534.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf537/cdefbf534.h
- * Based on:
- * Author:
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * Created:
- * Description: system mmr register map
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _CDEF_BF534_H
diff --git a/arch/blackfin/mach-bf537/include/mach/cdefBF537.h b/arch/blackfin/mach-bf537/include/mach/cdefBF537.h
index b8fc949a991f..9363c3990421 100644
--- a/arch/blackfin/mach-bf537/include/mach/cdefBF537.h
+++ b/arch/blackfin/mach-bf537/include/mach/cdefBF537.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf537/cdefBF537.h
- * Based on:
- * Author:
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- * System MMR Register Map
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later
*/
#ifndef _CDEF_BF537_H
diff --git a/arch/blackfin/mach-bf537/include/mach/defBF534.h b/arch/blackfin/mach-bf537/include/mach/defBF534.h
index a3227f9003ff..cebb14feb1ba 100644
--- a/arch/blackfin/mach-bf537/include/mach/defBF534.h
+++ b/arch/blackfin/mach-bf537/include/mach/defBF534.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf537/cdefBF537.h
- * Based on:
- * Author:
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF534_H
diff --git a/arch/blackfin/mach-bf537/include/mach/defBF537.h b/arch/blackfin/mach-bf537/include/mach/defBF537.h
index 3d6c83e31b1e..8cb5d5cf0c94 100644
--- a/arch/blackfin/mach-bf537/include/mach/defBF537.h
+++ b/arch/blackfin/mach-bf537/include/mach/defBF537.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf537/defbf537.h
- * based on:
- * author:
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * created:
- * description:
- * system mmr register map
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF537_H
diff --git a/arch/blackfin/mach-bf537/include/mach/gpio.h b/arch/blackfin/mach-bf537/include/mach/gpio.h
index d77a31e45a30..104bff85290d 100644
--- a/arch/blackfin/mach-bf537/include/mach/gpio.h
+++ b/arch/blackfin/mach-bf537/include/mach/gpio.h
@@ -1,7 +1,4 @@
/*
- * File: arch/blackfin/mach-bf537/include/mach/gpio.h
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
* Copyright (C) 2008 Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/mach-bf537/include/mach/irq.h b/arch/blackfin/mach-bf537/include/mach/irq.h
index b2a71d5d4e5f..0defa9457e7f 100644
--- a/arch/blackfin/mach-bf537/include/mach/irq.h
+++ b/arch/blackfin/mach-bf537/include/mach/irq.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf537/irq.h
- * based on:
- * author:
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * created:
- * description:
- * system mmr register map
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later
*/
#ifndef _BF537_IRQ_H_
diff --git a/arch/blackfin/mach-bf537/include/mach/portmux.h b/arch/blackfin/mach-bf537/include/mach/portmux.h
index 87285e75e903..da9760329e49 100644
--- a/arch/blackfin/mach-bf537/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf537/include/mach/portmux.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2007-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later
+ */
+
#ifndef _MACH_PORTMUX_H_
#define _MACH_PORTMUX_H_
diff --git a/arch/blackfin/mach-bf537/ints-priority.c b/arch/blackfin/mach-bf537/ints-priority.c
index 51c48087e03b..f6500622b35d 100644
--- a/arch/blackfin/mach-bf537/ints-priority.c
+++ b/arch/blackfin/mach-bf537/ints-priority.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-bf537/ints-priority.c
- * Based on: arch/blackfin/mach-bf533/ints-priority.c
- * Author: Michael Hennerich
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Created:
- * Description: Set up the interrupt priorities
+ * Licensed under the GPL-2 or later.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Set up the interrupt priorities
*/
#include <linux/module.h>
diff --git a/arch/blackfin/mach-bf538/boards/ezkit.c b/arch/blackfin/mach-bf538/boards/ezkit.c
index f2ac3b0ebf24..14af5c2088d4 100644
--- a/arch/blackfin/mach-bf538/boards/ezkit.c
+++ b/arch/blackfin/mach-bf538/boards/ezkit.c
@@ -1,31 +1,9 @@
/*
- * File: arch/blackfin/mach-bf538/boards/ezkit.c
- * Based on: arch/blackfin/mach-bf537/boards/ezkit.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2
*/
#include <linux/device.h>
@@ -237,7 +215,6 @@ static struct flash_platform_data bfin_spi_flash_data = {
static struct bfin5xx_spi_chip spi_flash_chip_info = {
.enable_dma = 0, /* use dma transfer with this chip*/
.bits_per_word = 8,
- .cs_change_per_word = 0,
};
#endif
@@ -506,19 +483,6 @@ static struct platform_device i2c_bfin_twi1_device = {
#endif
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
#include <linux/gpio_keys.h>
@@ -658,8 +622,6 @@ static struct platform_device *cm_bf538_devices[] __initdata = {
&bfin_device_gpiokeys,
#endif
- &bfin_gpios_device,
-
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
&ezkit_flash_device,
#endif
diff --git a/arch/blackfin/mach-bf538/dma.c b/arch/blackfin/mach-bf538/dma.c
index d6837fbf94ea..5dc022589214 100644
--- a/arch/blackfin/mach-bf538/dma.c
+++ b/arch/blackfin/mach-bf538/dma.c
@@ -1,31 +1,11 @@
/*
- * File: arch/blackfin/mach-bf538/dma.c
- * Based on:
- * Author:
+ * the simple DMA Implementation for Blackfin
*
- * Created:
- * Description: This file contains the simple DMA Implementation for Blackfin
+ * Copyright 2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
+
#include <linux/module.h>
#include <asm/blackfin.h>
diff --git a/arch/blackfin/mach-bf538/include/mach/bf538.h b/arch/blackfin/mach-bf538/include/mach/bf538.h
index 9c8abb307908..0cf5bf8dab84 100644
--- a/arch/blackfin/mach-bf538/include/mach/bf538.h
+++ b/arch/blackfin/mach-bf538/include/mach/bf538.h
@@ -1,30 +1,9 @@
/*
- * File: include/asm-blackfin/mach-bf538/bf538.h
- * Based on: include/asm-blackfin/mach-bf537/bf537.h
- * Author: Michael Hennerich (michael.hennerich@analog.com)
+ * SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF538
*
- * Created:
- * Description: SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF527
+ * Copyright 2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __MACH_BF538_H__
diff --git a/arch/blackfin/mach-bf538/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf538/include/mach/bfin_serial_5xx.h
index 999f239fe1a6..5c148142f041 100644
--- a/arch/blackfin/mach-bf538/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf538/include/mach/bfin_serial_5xx.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf538/bfin_serial_5xx.h
- * based on:
- * author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * created:
- * description:
- * blackfin serial driver header files
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later.
*/
#include <linux/serial.h>
diff --git a/arch/blackfin/mach-bf538/include/mach/blackfin.h b/arch/blackfin/mach-bf538/include/mach/blackfin.h
index 5ecee1690957..278e8942eef2 100644
--- a/arch/blackfin/mach-bf538/include/mach/blackfin.h
+++ b/arch/blackfin/mach-bf538/include/mach/blackfin.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf538/blackfin.h
- * Based on:
- * Author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _MACH_BLACKFIN_H_
diff --git a/arch/blackfin/mach-bf538/include/mach/cdefBF538.h b/arch/blackfin/mach-bf538/include/mach/cdefBF538.h
index 1de67515dc9d..401ebd79d0aa 100644
--- a/arch/blackfin/mach-bf538/include/mach/cdefBF538.h
+++ b/arch/blackfin/mach-bf538/include/mach/cdefBF538.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf538/cdefBF538.h
- * Based on:
- * Author:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _CDEF_BF538_H
diff --git a/arch/blackfin/mach-bf538/include/mach/defBF539.h b/arch/blackfin/mach-bf538/include/mach/defBF539.h
index 1c58914a8740..5f6c34dfd08e 100644
--- a/arch/blackfin/mach-bf538/include/mach/defBF539.h
+++ b/arch/blackfin/mach-bf538/include/mach/defBF539.h
@@ -1,47 +1,9 @@
-/************************************************************************
- *
- * This file is subject to the terms and conditions of the GNU Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Non-GPL License also available as part of VisualDSP++
- * http://www.analog.com/processors/resources/crosscore/visualDspDevSoftware.html
- *
- * (c) Copyright 2001-2005 Analog Devices, Inc. All rights reserved
- *
- * This file under source code control, please send bugs or changes to:
- * dsptools.support@analog.com
- *
- ************************************************************************/
/*
- * File: include/asm-blackfin/mach-bf538/defBF539.h
- * Based on:
- * Author:
- *
- * Created:
- * Description:
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
+
/* SYSTEM & MM REGISTER BIT & ADDRESS DEFINITIONS FOR ADSP-BF538/9 */
#ifndef _DEF_BF539_H
diff --git a/arch/blackfin/mach-bf538/include/mach/gpio.h b/arch/blackfin/mach-bf538/include/mach/gpio.h
index 30f4f723f7cc..295c78a465c2 100644
--- a/arch/blackfin/mach-bf538/include/mach/gpio.h
+++ b/arch/blackfin/mach-bf538/include/mach/gpio.h
@@ -1,7 +1,4 @@
/*
- * File: arch/blackfin/mach-bf538/include/mach/gpio.h
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
* Copyright (C) 2008 Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/mach-bf538/include/mach/irq.h b/arch/blackfin/mach-bf538/include/mach/irq.h
index fdc87fe2c174..a4b7fcbc556b 100644
--- a/arch/blackfin/mach-bf538/include/mach/irq.h
+++ b/arch/blackfin/mach-bf538/include/mach/irq.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf538/irq.h
- * based on: include/asm-blackfin/mach-bf537/irq.h
- * author: Michael Hennerich (michael.hennerich@analog.com)
+ * Copyright 2008 Analog Devices Inc.
*
- * created:
- * description:
- * system mmr register map
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _BF538_IRQ_H_
diff --git a/arch/blackfin/mach-bf538/include/mach/portmux.h b/arch/blackfin/mach-bf538/include/mach/portmux.h
index c8db264e3e4d..6121cf8b5872 100644
--- a/arch/blackfin/mach-bf538/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf538/include/mach/portmux.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2008-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _MACH_PORTMUX_H_
#define _MACH_PORTMUX_H_
diff --git a/arch/blackfin/mach-bf538/ints-priority.c b/arch/blackfin/mach-bf538/ints-priority.c
index 70d17e550e05..1fa793ced347 100644
--- a/arch/blackfin/mach-bf538/ints-priority.c
+++ b/arch/blackfin/mach-bf538/ints-priority.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-bf538/ints-priority.c
- * Based on: arch/blackfin/mach-bf533/ints-priority.c
- * Author: Michael Hennerich
+ * Set up the interrupt priorities
*
- * Created:
- * Description: Set up the interrupt priorities
+ * Copyright 2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
diff --git a/arch/blackfin/mach-bf548/boards/cm_bf548.c b/arch/blackfin/mach-bf548/boards/cm_bf548.c
index e565aae11d72..ccdcd6da2e9f 100644
--- a/arch/blackfin/mach-bf548/boards/cm_bf548.c
+++ b/arch/blackfin/mach-bf548/boards/cm_bf548.c
@@ -1,31 +1,10 @@
/*
- * File: arch/blackfin/mach-bf548/boards/cm_bf548.c
- * Based on: arch/blackfin/mach-bf537/boards/ezkit.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2008-2009 Bluetechnix
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -380,19 +359,6 @@ static struct platform_device musb_device = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_PATA_BF54X) || defined(CONFIG_PATA_BF54X_MODULE)
static struct resource bfin_atapi_resources[] = {
{
@@ -546,13 +512,11 @@ static struct flash_platform_data bfin_spi_flash_data = {
static struct bfin5xx_spi_chip spi_flash_chip_info = {
.enable_dma = 0, /* use dma transfer with this chip*/
.bits_per_word = 8,
- .cs_change_per_word = 0,
};
#endif
#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
- .cs_change_per_word = 0,
.enable_dma = 0,
.bits_per_word = 16,
};
@@ -853,8 +817,6 @@ static struct platform_device *cm_bf548_devices[] __initdata = {
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
&para_flash_device,
#endif
-
- &bfin_gpios_device,
};
static int __init cm_bf548_init(void)
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index c66f3801274f..1a5286bbb3fa 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -1,31 +1,9 @@
/*
- * File: arch/blackfin/mach-bf548/boards/ezkit.c
- * Based on: arch/blackfin/mach-bf537/boards/ezkit.c
- * Author: Aidan Williams <aidan@nicta.com.au>
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2005 National ICT Australia (NICTA)
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -208,7 +186,6 @@ static struct platform_device bfin_rotary_device = {
#endif
#if defined(CONFIG_INPUT_ADXL34X) || defined(CONFIG_INPUT_ADXL34X_MODULE)
-#include <linux/input.h>
#include <linux/spi/adxl34x.h>
static const struct adxl34x_platform_data adxl34x_info = {
.x_axis_offset = 0,
@@ -636,7 +613,6 @@ static struct flash_platform_data bfin_spi_flash_data = {
static struct bfin5xx_spi_chip spi_flash_chip_info = {
.enable_dma = 0, /* use dma transfer with this chip*/
.bits_per_word = 8,
- .cs_change_per_word = 0,
};
#endif
@@ -650,7 +626,6 @@ static struct bfin5xx_spi_chip ad1836_spi_chip_info = {
#if defined(CONFIG_TOUCHSCREEN_AD7877) || defined(CONFIG_TOUCHSCREEN_AD7877_MODULE)
static struct bfin5xx_spi_chip spi_ad7877_chip_info = {
- .cs_change_per_word = 0,
.enable_dma = 0,
.bits_per_word = 16,
};
@@ -681,7 +656,6 @@ static struct bfin5xx_spi_chip spidev_chip_info = {
static struct bfin5xx_spi_chip spi_adxl34x_chip_info = {
.enable_dma = 0, /* use dma transfer with this chip*/
.bits_per_word = 8,
- .cs_change_per_word = 0,
};
#endif
@@ -908,19 +882,6 @@ static struct platform_device bfin_device_gpiokeys = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
static const unsigned int cclk_vlev_datasheet[] =
{
/*
@@ -1028,8 +989,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
&bfin_device_gpiokeys,
#endif
- &bfin_gpios_device,
-
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
&ezkit_flash_device,
#endif
diff --git a/arch/blackfin/mach-bf548/dma.c b/arch/blackfin/mach-bf548/dma.c
index d9239bc05dd4..039a6d9d38f3 100644
--- a/arch/blackfin/mach-bf548/dma.c
+++ b/arch/blackfin/mach-bf548/dma.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-bf548/dma.c
- * Based on:
- * Author:
+ * the simple DMA Implementation for Blackfin
*
- * Created:
- * Description: This file contains the simple DMA Implementation for Blackfin
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
diff --git a/arch/blackfin/mach-bf548/include/mach/bf548.h b/arch/blackfin/mach-bf548/include/mach/bf548.h
index cd31f72bdd82..7bead5ce0f3b 100644
--- a/arch/blackfin/mach-bf548/include/mach/bf548.h
+++ b/arch/blackfin/mach-bf548/include/mach/bf548.h
@@ -1,30 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/bf548.h
- * Based on:
- * Author:
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Created:
- * Description: System MMR register and memory map for ADSP-BF548
- *
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __MACH_BF548_H__
diff --git a/arch/blackfin/mach-bf548/include/mach/bf54x-lq043.h b/arch/blackfin/mach-bf548/include/mach/bf54x-lq043.h
index 9c7ca62a45eb..8821efe57fbc 100644
--- a/arch/blackfin/mach-bf548/include/mach/bf54x-lq043.h
+++ b/arch/blackfin/mach-bf548/include/mach/bf54x-lq043.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef BF54X_LQ043_H
#define BF54X_LQ043_H
diff --git a/arch/blackfin/mach-bf548/include/mach/bf54x_keys.h b/arch/blackfin/mach-bf548/include/mach/bf54x_keys.h
index 1fb4ec77cc25..49338ae299ab 100644
--- a/arch/blackfin/mach-bf548/include/mach/bf54x_keys.h
+++ b/arch/blackfin/mach-bf548/include/mach/bf54x_keys.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _BFIN_KPAD_H
#define _BFIN_KPAD_H
diff --git a/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
index 2d1b5fa3cca0..dd44aa75fe72 100644
--- a/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf548/include/mach/bfin_serial_5xx.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf548/bfin_serial_5xx.h
- * based on:
- * author:
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * created:
- * description:
- * blackfin serial driver head file
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later.
*/
#include <linux/serial.h>
diff --git a/arch/blackfin/mach-bf548/include/mach/blackfin.h b/arch/blackfin/mach-bf548/include/mach/blackfin.h
index 318667b2f036..13302b67857a 100644
--- a/arch/blackfin/mach-bf548/include/mach/blackfin.h
+++ b/arch/blackfin/mach-bf548/include/mach/blackfin.h
@@ -1,32 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/blackfin.h
- * Based on:
- * Author:
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _MACH_BLACKFIN_H_
diff --git a/arch/blackfin/mach-bf548/include/mach/cdefBF542.h b/arch/blackfin/mach-bf548/include/mach/cdefBF542.h
index 07aefb9ed79b..42f4a9469549 100644
--- a/arch/blackfin/mach-bf548/include/mach/cdefBF542.h
+++ b/arch/blackfin/mach-bf548/include/mach/cdefBF542.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/cdefBF542.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _CDEF_BF542_H
diff --git a/arch/blackfin/mach-bf548/include/mach/cdefBF544.h b/arch/blackfin/mach-bf548/include/mach/cdefBF544.h
index 431a69278991..2207799575ff 100644
--- a/arch/blackfin/mach-bf548/include/mach/cdefBF544.h
+++ b/arch/blackfin/mach-bf548/include/mach/cdefBF544.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/cdefBF544.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _CDEF_BF544_H
diff --git a/arch/blackfin/mach-bf548/include/mach/cdefBF547.h b/arch/blackfin/mach-bf548/include/mach/cdefBF547.h
index 93376e90dfc5..423421515134 100644
--- a/arch/blackfin/mach-bf548/include/mach/cdefBF547.h
+++ b/arch/blackfin/mach-bf548/include/mach/cdefBF547.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/cdefBF547.h
- * Based on:
- * Author:
+ * Copyright 2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _CDEF_BF548_H
diff --git a/arch/blackfin/mach-bf548/include/mach/cdefBF548.h b/arch/blackfin/mach-bf548/include/mach/cdefBF548.h
index 9cd74384136f..df84180410c4 100644
--- a/arch/blackfin/mach-bf548/include/mach/cdefBF548.h
+++ b/arch/blackfin/mach-bf548/include/mach/cdefBF548.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/cdefBF548.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _CDEF_BF548_H
diff --git a/arch/blackfin/mach-bf548/include/mach/cdefBF549.h b/arch/blackfin/mach-bf548/include/mach/cdefBF549.h
index ead360b69dea..34c84c7fb256 100644
--- a/arch/blackfin/mach-bf548/include/mach/cdefBF549.h
+++ b/arch/blackfin/mach-bf548/include/mach/cdefBF549.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf549/cdefBF549.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _CDEF_BF549_H
diff --git a/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h b/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h
index 6e636c418cb0..a2e9d9849eba 100644
--- a/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h
+++ b/arch/blackfin/mach-bf548/include/mach/cdefBF54x_base.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/cdefBF54x_base.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _CDEF_BF54X_H
diff --git a/arch/blackfin/mach-bf548/include/mach/defBF542.h b/arch/blackfin/mach-bf548/include/mach/defBF542.h
index b1316541b8d6..d3bc6d1df547 100644
--- a/arch/blackfin/mach-bf548/include/mach/defBF542.h
+++ b/arch/blackfin/mach-bf548/include/mach/defBF542.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/defBF542.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF542_H
diff --git a/arch/blackfin/mach-bf548/include/mach/defBF544.h b/arch/blackfin/mach-bf548/include/mach/defBF544.h
index c2c785bdc5fc..dd414ae4ba4c 100644
--- a/arch/blackfin/mach-bf548/include/mach/defBF544.h
+++ b/arch/blackfin/mach-bf548/include/mach/defBF544.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/defBF544.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF544_H
diff --git a/arch/blackfin/mach-bf548/include/mach/defBF547.h b/arch/blackfin/mach-bf548/include/mach/defBF547.h
index 661f0d877bd1..5a9dbabe0a68 100644
--- a/arch/blackfin/mach-bf548/include/mach/defBF547.h
+++ b/arch/blackfin/mach-bf548/include/mach/defBF547.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/defBF547.h
- * Based on:
- * Author:
+ * Copyright 2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF548_H
diff --git a/arch/blackfin/mach-bf548/include/mach/defBF548.h b/arch/blackfin/mach-bf548/include/mach/defBF548.h
index 85d4bade911d..82cd593f7391 100644
--- a/arch/blackfin/mach-bf548/include/mach/defBF548.h
+++ b/arch/blackfin/mach-bf548/include/mach/defBF548.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/defBF548.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF548_H
diff --git a/arch/blackfin/mach-bf548/include/mach/defBF549.h b/arch/blackfin/mach-bf548/include/mach/defBF549.h
index 096734541644..6fc6e39ab61b 100644
--- a/arch/blackfin/mach-bf548/include/mach/defBF549.h
+++ b/arch/blackfin/mach-bf548/include/mach/defBF549.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/defBF549.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF549_H
diff --git a/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h b/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h
index e022e896cb18..8590c8c78336 100644
--- a/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h
+++ b/arch/blackfin/mach-bf548/include/mach/defBF54x_base.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf548/defBF54x_base.h
- * Based on:
- * Author:
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF54X_H
diff --git a/arch/blackfin/mach-bf548/include/mach/gpio.h b/arch/blackfin/mach-bf548/include/mach/gpio.h
index 3a2051709787..850e39d193e3 100644
--- a/arch/blackfin/mach-bf548/include/mach/gpio.h
+++ b/arch/blackfin/mach-bf548/include/mach/gpio.h
@@ -1,34 +1,8 @@
/*
- * File: include/asm-blackfin/mach-bf548/gpio.h
- * Based on:
- * Author: Michael Hennerich (hennerich@blackfin.uclinux.org)
- *
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Copyright 2007-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
*/
-
-
#define GPIO_PA0 0
#define GPIO_PA1 1
#define GPIO_PA2 2
diff --git a/arch/blackfin/mach-bf548/include/mach/irq.h b/arch/blackfin/mach-bf548/include/mach/irq.h
index f194625f6821..106db05684ae 100644
--- a/arch/blackfin/mach-bf548/include/mach/irq.h
+++ b/arch/blackfin/mach-bf548/include/mach/irq.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf548/irq.h
- * based on: include/asm-blackfin/mach-bf537/irq.h
- * author: Roy Huang (roy.huang@analog.com)
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * created:
- * description:
- * system mmr register map
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _BF548_IRQ_H_
diff --git a/arch/blackfin/mach-bf548/include/mach/portmux.h b/arch/blackfin/mach-bf548/include/mach/portmux.h
index ce372ba0f046..89ad6a886362 100644
--- a/arch/blackfin/mach-bf548/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf548/include/mach/portmux.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2007-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _MACH_PORTMUX_H_
#define _MACH_PORTMUX_H_
diff --git a/arch/blackfin/mach-bf548/ints-priority.c b/arch/blackfin/mach-bf548/ints-priority.c
index 9dd0fa3ac4de..48dd3a4bc4a5 100644
--- a/arch/blackfin/mach-bf548/ints-priority.c
+++ b/arch/blackfin/mach-bf548/ints-priority.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-bf537/ints-priority.c
- * Based on: arch/blackfin/mach-bf533/ints-priority.c
- * Author: Michael Hennerich
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Created:
- * Description: Set up the interrupt priorities
+ * Licensed under the GPL-2 or later.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Set up the interrupt priorities
*/
#include <linux/module.h>
diff --git a/arch/blackfin/mach-bf561/atomic.S b/arch/blackfin/mach-bf561/atomic.S
index 9439bc6bd01f..0261a5e751b3 100644
--- a/arch/blackfin/mach-bf561/atomic.S
+++ b/arch/blackfin/mach-bf561/atomic.S
@@ -1,23 +1,8 @@
/*
- * File: arch/blackfin/mach-bf561/atomic.S
- * Author: Philippe Gerum <rpm@xenomai.org>
+ * Copyright 2007-2008 Analog Devices Inc.
+ * Philippe Gerum <rpm@xenomai.org>
*
- * Copyright 2007 Analog Devices Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/linkage.h>
diff --git a/arch/blackfin/mach-bf561/boards/cm_bf561.c b/arch/blackfin/mach-bf561/boards/cm_bf561.c
index 6577ecfcf11e..dfc8d5b77986 100644
--- a/arch/blackfin/mach-bf561/boards/cm_bf561.c
+++ b/arch/blackfin/mach-bf561/boards/cm_bf561.c
@@ -1,30 +1,10 @@
/*
- * File: arch/blackfin/mach-bf533/boards/cm_bf561.c
- * Based on: arch/blackfin/mach-bf533/boards/ezkit.c
- * Author: Aidan Williams <aidan@nicta.com.au> Copyright 2005
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2008-2009 Bluetechnix
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created: 2006
- * Description: Board description file
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -285,19 +265,6 @@ static struct platform_device net2272_bfin_device = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_USB_ISP1362_HCD) || defined(CONFIG_USB_ISP1362_HCD_MODULE)
static struct resource isp1362_hcd_resources[] = {
{
@@ -532,8 +499,6 @@ static struct platform_device *cm_bf561_devices[] __initdata = {
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
&para_flash_device,
#endif
-
- &bfin_gpios_device,
};
static int __init cm_bf561_init(void)
diff --git a/arch/blackfin/mach-bf561/boards/ezkit.c b/arch/blackfin/mach-bf561/boards/ezkit.c
index caed96bb957e..9e2d8cfba546 100644
--- a/arch/blackfin/mach-bf561/boards/ezkit.c
+++ b/arch/blackfin/mach-bf561/boards/ezkit.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-bf561/ezkit.c
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/device.h>
@@ -387,19 +366,6 @@ static struct platform_device bfin_device_gpiokeys = {
};
#endif
-static struct resource bfin_gpios_resources = {
- .start = 0,
- .end = MAX_BLACKFIN_GPIOS - 1,
- .flags = IORESOURCE_IRQ,
-};
-
-static struct platform_device bfin_gpios_device = {
- .name = "simple-gpio",
- .id = -1,
- .num_resources = 1,
- .resource = &bfin_gpios_resources,
-};
-
#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
#include <linux/i2c-gpio.h>
@@ -493,8 +459,6 @@ static struct platform_device *ezkit_devices[] __initdata = {
&isp1362_hcd_device,
#endif
- &bfin_gpios_device,
-
#if defined(CONFIG_MTD_PHYSMAP) || defined(CONFIG_MTD_PHYSMAP_MODULE)
&ezkit_flash_device,
#endif
diff --git a/arch/blackfin/mach-bf561/boards/tepla.c b/arch/blackfin/mach-bf561/boards/tepla.c
index 6f77dbe952f5..8ba7252455e1 100644
--- a/arch/blackfin/mach-bf561/boards/tepla.c
+++ b/arch/blackfin/mach-bf561/boards/tepla.c
@@ -1,15 +1,13 @@
/*
- * File: arch/blackfin/mach-bf561/tepla.c
+ * Copyright 2004-2007 Analog Devices Inc.
+ * 2005 National ICT Australia (NICTA)
+ * Aidan Williams <aidan@nicta.com.au>
*
- * Copyright 2004-2007 Analog Devices Inc.
- * Only SMSC91C1111 was registered, may do more later.
+ * Thanks to Jamey Hicks.
*
- * Copyright 2005 National ICT Australia (NICTA), Aidan Williams <aidan@nicta.com.au>
- * Thanks to Jamey Hicks.
+ * Only SMSC91C1111 was registered, may do more later.
*
- * 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.
+ * Licensed under the GPL-2
*/
#include <linux/device.h>
diff --git a/arch/blackfin/mach-bf561/dma.c b/arch/blackfin/mach-bf561/dma.c
index 42b0037afe61..c938c3c7355d 100644
--- a/arch/blackfin/mach-bf561/dma.c
+++ b/arch/blackfin/mach-bf561/dma.c
@@ -1,31 +1,11 @@
/*
- * File: arch/blackfin/mach-bf561/dma.c
- * Based on:
- * Author:
+ * the simple DMA Implementation for Blackfin
*
- * Created:
- * Description: This file contains the simple DMA Implementation for Blackfin
+ * Copyright 2007-2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
+
#include <linux/module.h>
#include <asm/blackfin.h>
diff --git a/arch/blackfin/mach-bf561/include/mach/bf561.h b/arch/blackfin/mach-bf561/include/mach/bf561.h
index 9968362a2ee4..9f9a367e6a24 100644
--- a/arch/blackfin/mach-bf561/include/mach/bf561.h
+++ b/arch/blackfin/mach-bf561/include/mach/bf561.h
@@ -1,30 +1,9 @@
/*
- * File: include/asm-blackfin/mach-bf561/bf561.h
- * Based on:
- * Author:
+ * SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
*
- * Created:
- * Description: SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __MACH_BF561_H__
diff --git a/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h b/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
index fd5e8878b8c4..e33e158bc16d 100644
--- a/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
+++ b/arch/blackfin/mach-bf561/include/mach/bfin_serial_5xx.h
@@ -1,32 +1,7 @@
/*
- * file: include/asm-blackfin/mach-bf561/bfin_serial_5xx.h
- * based on:
- * author:
+ * Copyright 2006-2009 Analog Devices Inc.
*
- * created:
- * description:
- * blackfin serial driver head file
- * rev:
- *
- * modified:
- *
- *
- * bugs: enter bugs at http://blackfin.uclinux.org/
- *
- * this program is free software; you can redistribute it and/or modify
- * it under the terms of the gnu general public license as published by
- * the free software foundation; either version 2, or (at your option)
- * any later version.
- *
- * this program is distributed in the hope that it will be useful,
- * but without any warranty; without even the implied warranty of
- * merchantability or fitness for a particular purpose. see the
- * gnu general public license for more details.
- *
- * you should have received a copy of the gnu general public license
- * along with this program; see the file copying.
- * if not, write to the free software foundation,
- * 59 temple place - suite 330, boston, ma 02111-1307, usa.
+ * Licensed under the GPL-2 or later.
*/
#include <linux/serial.h>
diff --git a/arch/blackfin/mach-bf561/include/mach/blackfin.h b/arch/blackfin/mach-bf561/include/mach/blackfin.h
index 8be31358ef88..67d6bdcd3fa8 100644
--- a/arch/blackfin/mach-bf561/include/mach/blackfin.h
+++ b/arch/blackfin/mach-bf561/include/mach/blackfin.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf561/blackfin.h
- * Based on:
- * Author:
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _MACH_BLACKFIN_H_
diff --git a/arch/blackfin/mach-bf561/include/mach/cdefBF561.h b/arch/blackfin/mach-bf561/include/mach/cdefBF561.h
index 9d9858c2be68..81ecdb71c6af 100644
--- a/arch/blackfin/mach-bf561/include/mach/cdefBF561.h
+++ b/arch/blackfin/mach-bf561/include/mach/cdefBF561.h
@@ -1,31 +1,7 @@
/*
- * File: include/asm-blackfin/mach-bf561/cdefBF561.h
- * Based on:
- * Author:
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Created:
- * Description: C POINTERS TO SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _CDEF_BF561_H
diff --git a/arch/blackfin/mach-bf561/include/mach/defBF561.h b/arch/blackfin/mach-bf561/include/mach/defBF561.h
index 5fc0f05026e0..a31e509553fb 100644
--- a/arch/blackfin/mach-bf561/include/mach/defBF561.h
+++ b/arch/blackfin/mach-bf561/include/mach/defBF561.h
@@ -1,32 +1,7 @@
-
/*
- * File: include/asm-blackfin/mach-bf561/defBF561.h
- * Based on:
- * Author:
- *
- * Created:
- * Description:
- * SYSTEM MMR REGISTER AND MEMORY MAP FOR ADSP-BF561
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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.
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the ADI BSD license or the GPL-2 (or later)
*/
#ifndef _DEF_BF561_H
diff --git a/arch/blackfin/mach-bf561/include/mach/gpio.h b/arch/blackfin/mach-bf561/include/mach/gpio.h
index 7882f79e1ade..a651a8cf805f 100644
--- a/arch/blackfin/mach-bf561/include/mach/gpio.h
+++ b/arch/blackfin/mach-bf561/include/mach/gpio.h
@@ -1,7 +1,4 @@
/*
- * File: arch/blackfin/mach-bf561/include/mach/gpio.h
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
* Copyright (C) 2008 Analog Devices Inc.
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/mach-bf561/include/mach/irq.h b/arch/blackfin/mach-bf561/include/mach/irq.h
index 6698389c5564..7b208db267bf 100644
--- a/arch/blackfin/mach-bf561/include/mach/irq.h
+++ b/arch/blackfin/mach-bf561/include/mach/irq.h
@@ -1,32 +1,7 @@
-
/*
- * File: include/asm-blackfin/mach-bf561/irq.h
- * Based on:
- * Author:
- *
- * Created:
- * Description:
- *
- * Rev:
- *
- * Modified:
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, 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.
+ * Copyright 2005-2008 Analog Devices Inc.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING.
- * If not, write to the Free Software Foundation,
- * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Licensed under the GPL-2 or later.
*/
#ifndef _BF561_IRQ_H_
diff --git a/arch/blackfin/mach-bf561/include/mach/portmux.h b/arch/blackfin/mach-bf561/include/mach/portmux.h
index 2e5ad6347dea..3a7b46bbe849 100644
--- a/arch/blackfin/mach-bf561/include/mach/portmux.h
+++ b/arch/blackfin/mach-bf561/include/mach/portmux.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2007-2009 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _MACH_PORTMUX_H_
#define _MACH_PORTMUX_H_
diff --git a/arch/blackfin/mach-bf561/include/mach/smp.h b/arch/blackfin/mach-bf561/include/mach/smp.h
index f9e65ebe81b2..390c7f4ae7b3 100644
--- a/arch/blackfin/mach-bf561/include/mach/smp.h
+++ b/arch/blackfin/mach-bf561/include/mach/smp.h
@@ -1,3 +1,9 @@
+/*
+ * Copyright 2007-2008 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
#ifndef _MACH_BF561_SMP
#define _MACH_BF561_SMP
diff --git a/arch/blackfin/mach-bf561/ints-priority.c b/arch/blackfin/mach-bf561/ints-priority.c
index 9d2f23344720..b4424172ad9e 100644
--- a/arch/blackfin/mach-bf561/ints-priority.c
+++ b/arch/blackfin/mach-bf561/ints-priority.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-bf561/ints-priority.c
- * Based on: arch/blackfin/mach-bf537/ints-priority.c
- * Author: Michael Hennerich
+ * Set up the interrupt priorities
*
- * Created:
- * Description: Set up the interrupt priorities
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
diff --git a/arch/blackfin/mach-bf561/secondary.S b/arch/blackfin/mach-bf561/secondary.S
index f72a6af20c4f..8e6050369c06 100644
--- a/arch/blackfin/mach-bf561/secondary.S
+++ b/arch/blackfin/mach-bf561/secondary.S
@@ -1,26 +1,10 @@
/*
- * File: arch/blackfin/mach-bf561/secondary.S
- * Based on: arch/blackfin/mach-bf561/head.S
- * Author: Philippe Gerum <rpm@xenomai.org>
+ * BF561 coreB bootstrap file
*
- * Copyright 2007 Analog Devices Inc.
+ * Copyright 2007-2009 Analog Devices Inc.
+ * Philippe Gerum <rpm@xenomai.org>
*
- * Description: BF561 coreB bootstrap file
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/linkage.h>
diff --git a/arch/blackfin/mach-bf561/smp.c b/arch/blackfin/mach-bf561/smp.c
index 8c10701c251f..510f57641495 100644
--- a/arch/blackfin/mach-bf561/smp.c
+++ b/arch/blackfin/mach-bf561/smp.c
@@ -1,23 +1,8 @@
/*
- * File: arch/blackfin/mach-bf561/smp.c
- * Author: Philippe Gerum <rpm@xenomai.org>
+ * Copyright 2007-2009 Analog Devices Inc.
+ * Philippe Gerum <rpm@xenomai.org>
*
- * Copyright 2007 Analog Devices Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/init.h>
diff --git a/arch/blackfin/mach-common/arch_checks.c b/arch/blackfin/mach-common/arch_checks.c
index 5998d8632a73..9dbafcdcf479 100644
--- a/arch/blackfin/mach-common/arch_checks.c
+++ b/arch/blackfin/mach-common/arch_checks.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-common/arch_checks.c
- * Based on:
- * Author: Robin Getz <rgetz@blackfin.uclinux.org>
+ * Do some checking to make sure things are OK
*
- * Created: 25Jul07
- * Description: Do some checking to make sure things are OK
+ * Copyright 2007-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <asm/fixed_code.h>
diff --git a/arch/blackfin/mach-common/cache-c.c b/arch/blackfin/mach-common/cache-c.c
index 4ebbd78db3a4..a60a24f5035d 100644
--- a/arch/blackfin/mach-common/cache-c.c
+++ b/arch/blackfin/mach-common/cache-c.c
@@ -3,8 +3,6 @@
*
* Copyright 2004-2009 Analog Devices Inc.
*
- * Enter bugs at http://blackfin.uclinux.org/
- *
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/mach-common/cache.S b/arch/blackfin/mach-common/cache.S
index d9666fe6c3d6..ea540318a228 100644
--- a/arch/blackfin/mach-common/cache.S
+++ b/arch/blackfin/mach-common/cache.S
@@ -3,8 +3,6 @@
*
* Copyright 2004-2008 Analog Devices Inc.
*
- * Enter bugs at http://blackfin.uclinux.org/
- *
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/mach-common/cpufreq.c b/arch/blackfin/mach-common/cpufreq.c
index 85c658083279..01506504e6d0 100644
--- a/arch/blackfin/mach-common/cpufreq.c
+++ b/arch/blackfin/mach-common/cpufreq.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-common/cpufreq.c
- * Based on:
- * Author:
+ * Blackfin core clock scaling
*
- * Created:
- * Description: Blackfin core clock scaling
+ * Copyright 2008-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/kernel.h>
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S
index 1e7cac23e25f..a50637a8b9bd 100644
--- a/arch/blackfin/mach-common/entry.S
+++ b/arch/blackfin/mach-common/entry.S
@@ -1,32 +1,11 @@
/*
- * File: arch/blackfin/mach-common/entry.S
- * Based on:
- * Author: Linus Torvalds
+ * Contains the system-call and fault low-level handling routines.
+ * This also contains the timer-interrupt handler, as well as all
+ * interrupts and faults that can result in a task-switch.
*
- * Created: ?
- * Description: contains the system-call and fault low-level handling routines.
- * This also contains the timer-interrupt handler, as well as all
- * interrupts and faults that can result in a task-switch.
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
/* NOTE: This code handles signal-recognition, which happens every time
@@ -1621,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/blackfin/mach-common/head.S b/arch/blackfin/mach-common/head.S
index 9c79dfea2a53..cab0a0031eee 100644
--- a/arch/blackfin/mach-common/head.S
+++ b/arch/blackfin/mach-common/head.S
@@ -3,8 +3,6 @@
*
* Copyright 2004-2008 Analog Devices Inc.
*
- * Enter bugs at http://blackfin.uclinux.org/
- *
* Licensed under the GPL-2 or later.
*/
diff --git a/arch/blackfin/mach-common/interrupt.S b/arch/blackfin/mach-common/interrupt.S
index 82d417ef4b5b..8085ff1cce00 100644
--- a/arch/blackfin/mach-common/interrupt.S
+++ b/arch/blackfin/mach-common/interrupt.S
@@ -1,31 +1,11 @@
/*
- * File: arch/blackfin/mach-common/interrupt.S
- * Based on:
- * Author: D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>
- * Kenneth Albanowski <kjahds@kjahds.com>
- *
- * Created: ?
- * Description: Interrupt Entries
- *
- * Modified:
- * Copyright 2004-2006 Analog Devices Inc.
+ * Interrupt Entries
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * Copyright 2005-2009 Analog Devices Inc.
+ * D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>
+ * Kenneth Albanowski <kjahds@kjahds.com>
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <asm/blackfin.h>
diff --git a/arch/blackfin/mach-common/ints-priority.c b/arch/blackfin/mach-common/ints-priority.c
index 6ffda78aaf9d..660ea1bec54c 100644
--- a/arch/blackfin/mach-common/ints-priority.c
+++ b/arch/blackfin/mach-common/ints-priority.c
@@ -1,33 +1,14 @@
/*
- * File: arch/blackfin/mach-common/ints-priority.c
+ * Set up the interrupt priorities
*
- * Description: Set up the interrupt priorities
+ * Copyright 2004-2009 Analog Devices Inc.
+ * 2003 Bas Vermeulen <bas@buyways.nl>
+ * 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
+ * 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca>
+ * 1999 D. Jeff Dionne <jeff@uclinux.org>
+ * 1996 Roman Zippel
*
- * Modified:
- * 1996 Roman Zippel
- * 1999 D. Jeff Dionne <jeff@uclinux.org>
- * 2000-2001 Lineo, Inc. D. Jefff Dionne <jeff@lineo.ca>
- * 2002 Arcturus Networks Inc. MaTed <mated@sympatico.ca>
- * 2003 Metrowerks/Motorola
- * 2003 Bas Vermeulen <bas@buyways.nl>
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2
*/
#include <linux/module.h>
diff --git a/arch/blackfin/mach-common/irqpanic.c b/arch/blackfin/mach-common/irqpanic.c
index 883e3241b17e..c6496249e2bc 100644
--- a/arch/blackfin/mach-common/irqpanic.c
+++ b/arch/blackfin/mach-common/irqpanic.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mach-common/irqpanic.c
- * Based on:
- * Author:
+ * panic kernel with dump information
*
- * Created: ?
- * Description: panic kernel with dump information
+ * Copyright 2005-2009 Analog Devices Inc.
*
- * Modified: rgetz - added cache checking code 14Feb06
- * Copyright 2004-2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
diff --git a/arch/blackfin/mach-common/pm.c b/arch/blackfin/mach-common/pm.c
index 0e3d4ff9d8b6..8837be4edb4a 100644
--- a/arch/blackfin/mach-common/pm.c
+++ b/arch/blackfin/mach-common/pm.c
@@ -1,35 +1,11 @@
/*
- * File: arch/blackfin/mach-common/pm.c
- * Based on: arm/mach-omap/pm.c
- * Author: Cliff Brake <cbrake@accelent.com> Copyright (c) 2001
+ * Blackfin power management
*
- * Created: 2001
- * Description: Blackfin power management
+ * Copyright 2006-2009 Analog Devices Inc.
*
- * Modified: Nicolas Pitre - PXA250 support
- * Copyright (c) 2002 Monta Vista Software, Inc.
- * David Singleton - OMAP1510
- * Copyright (c) 2002 Monta Vista Software, Inc.
- * Dirk Behme <dirk.behme@de.bosch.com> - OMAP1510/1610
- * Copyright 2004
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2
+ * based on arm/mach-omap/pm.c
+ * Copyright 2001, Cliff Brake <cbrake@accelent.com> and others
*/
#include <linux/suspend.h>
diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c
index 349ee3f5466a..d98585f3237d 100644
--- a/arch/blackfin/mach-common/smp.c
+++ b/arch/blackfin/mach-common/smp.c
@@ -1,24 +1,10 @@
/*
- * File: arch/blackfin/kernel/smp.c
- * Author: Philippe Gerum <rpm@xenomai.org>
- * IPI management based on arch/arm/kernel/smp.c.
+ * IPI management based on arch/arm/kernel/smp.c (Copyright 2002 ARM Limited)
*
- * Copyright 2007 Analog Devices Inc.
+ * Copyright 2007-2009 Analog Devices Inc.
+ * Philippe Gerum <rpm@xenomai.org>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2.
*/
#include <linux/module.h>
diff --git a/arch/blackfin/mm/blackfin_sram.h b/arch/blackfin/mm/blackfin_sram.h
index bc0062884fde..fb0b1599cfb7 100644
--- a/arch/blackfin/mm/blackfin_sram.h
+++ b/arch/blackfin/mm/blackfin_sram.h
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mm/blackfin_sram.h
- * Based on: arch/blackfin/mm/blackfin_sram.c
- * Author: Mike Frysinger
+ * Local prototypes meant for internal use only
*
- * Created: Aug 2006
- * Description: Local prototypes meant for internal use only
+ * Copyright 2006-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2006 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#ifndef __BLACKFIN_SRAM_H__
diff --git a/arch/blackfin/mm/init.c b/arch/blackfin/mm/init.c
index b88ce7fda548..bb9c98f9cb5b 100644
--- a/arch/blackfin/mm/init.c
+++ b/arch/blackfin/mm/init.c
@@ -1,30 +1,7 @@
/*
- * File: arch/blackfin/mm/init.c
- * Based on:
- * Author:
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Created:
- * Description:
- *
- * Modified:
- * Copyright 2004-2007 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/swap.h>
diff --git a/arch/blackfin/mm/isram-driver.c b/arch/blackfin/mm/isram-driver.c
index beb1a608824c..84cdc5a1c139 100644
--- a/arch/blackfin/mm/isram-driver.c
+++ b/arch/blackfin/mm/isram-driver.c
@@ -1,19 +1,9 @@
/*
- * Description: Instruction SRAM accessor functions for the Blackfin
+ * Instruction SRAM accessor functions for the Blackfin
*
* Copyright 2008 Analog Devices Inc.
*
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later
*/
#define pr_fmt(fmt) "isram: " fmt
diff --git a/arch/blackfin/mm/sram-alloc.c b/arch/blackfin/mm/sram-alloc.c
index eb63ab353e5a..f068c11ea98f 100644
--- a/arch/blackfin/mm/sram-alloc.c
+++ b/arch/blackfin/mm/sram-alloc.c
@@ -1,30 +1,9 @@
/*
- * File: arch/blackfin/mm/sram-alloc.c
- * Based on:
- * Author:
+ * SRAM allocator for Blackfin on-chip memory
*
- * Created:
- * Description: SRAM allocator for Blackfin L1 and L2 memory
+ * Copyright 2004-2009 Analog Devices Inc.
*
- * Modified:
- * Copyright 2004-2008 Analog Devices Inc.
- *
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see the file COPYING, or write
- * to the Free Software Foundation, Inc.,
- * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the GPL-2 or later.
*/
#include <linux/module.h>
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/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/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/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/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/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/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/pci/pci.c b/arch/ia64/pci/pci.c
index 7de76dd352fe..d60e7195b7dd 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)
@@ -715,9 +720,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 +728,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 +748,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 +779,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/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c
index 1b7598e6f6e8..8a88f1f0a3e2 100644
--- a/arch/m32r/kernel/smp.c
+++ b/arch/m32r/kernel/smp.c
@@ -17,6 +17,7 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/smp.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/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c
index 594ee0e657fe..9a8876f715d8 100644
--- a/arch/m68knommu/kernel/asm-offsets.c
+++ b/arch/m68knommu/kernel/asm-offsets.c
@@ -45,25 +45,25 @@ int main(void)
DEFINE(THREAD_FPSTATE, offsetof(struct thread_struct, fpstate));
/* offsets into the pt_regs */
- DEFINE(PT_D0, offsetof(struct pt_regs, d0));
- DEFINE(PT_ORIG_D0, offsetof(struct pt_regs, orig_d0));
- DEFINE(PT_D1, offsetof(struct pt_regs, d1));
- DEFINE(PT_D2, offsetof(struct pt_regs, d2));
- DEFINE(PT_D3, offsetof(struct pt_regs, d3));
- DEFINE(PT_D4, offsetof(struct pt_regs, d4));
- DEFINE(PT_D5, offsetof(struct pt_regs, d5));
- DEFINE(PT_A0, offsetof(struct pt_regs, a0));
- DEFINE(PT_A1, offsetof(struct pt_regs, a1));
- DEFINE(PT_A2, offsetof(struct pt_regs, a2));
- DEFINE(PT_PC, offsetof(struct pt_regs, pc));
- DEFINE(PT_SR, offsetof(struct pt_regs, sr));
+ DEFINE(PT_OFF_D0, offsetof(struct pt_regs, d0));
+ DEFINE(PT_OFF_ORIG_D0, offsetof(struct pt_regs, orig_d0));
+ DEFINE(PT_OFF_D1, offsetof(struct pt_regs, d1));
+ DEFINE(PT_OFF_D2, offsetof(struct pt_regs, d2));
+ DEFINE(PT_OFF_D3, offsetof(struct pt_regs, d3));
+ DEFINE(PT_OFF_D4, offsetof(struct pt_regs, d4));
+ DEFINE(PT_OFF_D5, offsetof(struct pt_regs, d5));
+ DEFINE(PT_OFF_A0, offsetof(struct pt_regs, a0));
+ DEFINE(PT_OFF_A1, offsetof(struct pt_regs, a1));
+ DEFINE(PT_OFF_A2, offsetof(struct pt_regs, a2));
+ DEFINE(PT_OFF_PC, offsetof(struct pt_regs, pc));
+ DEFINE(PT_OFF_SR, offsetof(struct pt_regs, sr));
#ifdef CONFIG_COLDFIRE
/* bitfields are a bit difficult */
- DEFINE(PT_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
+ DEFINE(PT_OFF_FORMATVEC, offsetof(struct pt_regs, sr) - 2);
#else
/* bitfields are a bit difficult */
- DEFINE(PT_VECTOR, offsetof(struct pt_regs, pc) + 4);
+ DEFINE(PT_OFF_VECTOR, offsetof(struct pt_regs, pc) + 4);
#endif
/* signal defines */
diff --git a/arch/m68knommu/kernel/entry.S b/arch/m68knommu/kernel/entry.S
index f56faa5c9cd9..56043ade3941 100644
--- a/arch/m68knommu/kernel/entry.S
+++ b/arch/m68knommu/kernel/entry.S
@@ -46,7 +46,7 @@
ENTRY(buserr)
SAVE_ALL
moveq #-1,%d0
- movel %d0,%sp@(PT_ORIG_D0)
+ movel %d0,%sp@(PT_OFF_ORIG_D0)
movel %sp,%sp@- /* stack frame pointer argument */
jsr buserr_c
addql #4,%sp
@@ -55,7 +55,7 @@ ENTRY(buserr)
ENTRY(trap)
SAVE_ALL
moveq #-1,%d0
- movel %d0,%sp@(PT_ORIG_D0)
+ movel %d0,%sp@(PT_OFF_ORIG_D0)
movel %sp,%sp@- /* stack frame pointer argument */
jsr trap_c
addql #4,%sp
@@ -67,7 +67,7 @@ ENTRY(trap)
ENTRY(dbginterrupt)
SAVE_ALL
moveq #-1,%d0
- movel %d0,%sp@(PT_ORIG_D0)
+ movel %d0,%sp@(PT_OFF_ORIG_D0)
movel %sp,%sp@- /* stack frame pointer argument */
jsr dbginterrupt_c
addql #4,%sp
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/m68knommu/mm/init.c b/arch/m68knommu/mm/init.c
index b1703c67a4f1..f3236d0b522d 100644
--- a/arch/m68knommu/mm/init.c
+++ b/arch/m68knommu/mm/init.c
@@ -162,7 +162,7 @@ void free_initrd_mem(unsigned long start, unsigned long end)
totalram_pages++;
pages++;
}
- printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages);
+ printk (KERN_NOTICE "Freeing initrd memory: %dk freed\n", pages * (PAGE_SIZE / 1024));
}
#endif
diff --git a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c
index 0f41ba82a3b5..942397984c66 100644
--- a/arch/m68knommu/platform/5206e/config.c
+++ b/arch/m68knommu/platform/5206e/config.c
@@ -17,7 +17,6 @@
#include <asm/mcfsim.h>
#include <asm/mcfuart.h>
#include <asm/mcfdma.h>
-#include <asm/mcfuart.h>
/***************************************************************************/
diff --git a/arch/m68knommu/platform/68328/entry.S b/arch/m68knommu/platform/68328/entry.S
index b1aef72f3baf..9d80d2c42866 100644
--- a/arch/m68knommu/platform/68328/entry.S
+++ b/arch/m68knommu/platform/68328/entry.S
@@ -39,17 +39,17 @@
.globl inthandler7
badsys:
- movel #-ENOSYS,%sp@(PT_D0)
+ movel #-ENOSYS,%sp@(PT_OFF_D0)
jra ret_from_exception
do_trace:
- movel #-ENOSYS,%sp@(PT_D0) /* needed for strace*/
+ movel #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
subql #4,%sp
SAVE_SWITCH_STACK
jbsr syscall_trace
RESTORE_SWITCH_STACK
addql #4,%sp
- movel %sp@(PT_ORIG_D0),%d1
+ movel %sp@(PT_OFF_ORIG_D0),%d1
movel #-ENOSYS,%d0
cmpl #NR_syscalls,%d1
jcc 1f
@@ -57,7 +57,7 @@ do_trace:
lea sys_call_table, %a0
jbsr %a0@(%d1)
-1: movel %d0,%sp@(PT_D0) /* save the return value */
+1: movel %d0,%sp@(PT_OFF_D0) /* save the return value */
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
jbsr syscall_trace
@@ -75,7 +75,7 @@ ENTRY(system_call)
jbsr set_esp0
addql #4,%sp
- movel %sp@(PT_ORIG_D0),%d0
+ movel %sp@(PT_OFF_ORIG_D0),%d0
movel %sp,%d1 /* get thread_info pointer */
andl #-THREAD_SIZE,%d1
@@ -88,10 +88,10 @@ ENTRY(system_call)
lea sys_call_table,%a0
movel %a0@(%d0), %a0
jbsr %a0@
- movel %d0,%sp@(PT_D0) /* save the return value*/
+ movel %d0,%sp@(PT_OFF_D0) /* save the return value*/
ret_from_exception:
- btst #5,%sp@(PT_SR) /* check if returning to kernel*/
+ btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel*/
jeq Luser_return /* if so, skip resched, signals*/
Lkernel_return:
@@ -133,7 +133,7 @@ Lreturn:
*/
inthandler1:
SAVE_ALL
- movew %sp@(PT_VECTOR), %d0
+ movew %sp@(PT_OFF_VECTOR), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -144,7 +144,7 @@ inthandler1:
inthandler2:
SAVE_ALL
- movew %sp@(PT_VECTOR), %d0
+ movew %sp@(PT_OFF_VECTOR), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -155,7 +155,7 @@ inthandler2:
inthandler3:
SAVE_ALL
- movew %sp@(PT_VECTOR), %d0
+ movew %sp@(PT_OFF_VECTOR), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -166,7 +166,7 @@ inthandler3:
inthandler4:
SAVE_ALL
- movew %sp@(PT_VECTOR), %d0
+ movew %sp@(PT_OFF_VECTOR), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -177,7 +177,7 @@ inthandler4:
inthandler5:
SAVE_ALL
- movew %sp@(PT_VECTOR), %d0
+ movew %sp@(PT_OFF_VECTOR), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -188,7 +188,7 @@ inthandler5:
inthandler6:
SAVE_ALL
- movew %sp@(PT_VECTOR), %d0
+ movew %sp@(PT_OFF_VECTOR), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -199,7 +199,7 @@ inthandler6:
inthandler7:
SAVE_ALL
- movew %sp@(PT_VECTOR), %d0
+ movew %sp@(PT_OFF_VECTOR), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -210,7 +210,7 @@ inthandler7:
inthandler:
SAVE_ALL
- movew %sp@(PT_VECTOR), %d0
+ movew %sp@(PT_OFF_VECTOR), %d0
and #0x3ff, %d0
movel %sp,%sp@-
@@ -224,7 +224,7 @@ ret_from_interrupt:
2:
RESTORE_ALL
1:
- moveb %sp@(PT_SR), %d0
+ moveb %sp@(PT_OFF_SR), %d0
and #7, %d0
jhi 2b
diff --git a/arch/m68knommu/platform/68360/entry.S b/arch/m68knommu/platform/68360/entry.S
index 55dfefe38642..6d3460a39cac 100644
--- a/arch/m68knommu/platform/68360/entry.S
+++ b/arch/m68knommu/platform/68360/entry.S
@@ -35,17 +35,17 @@
.globl inthandler
badsys:
- movel #-ENOSYS,%sp@(PT_D0)
+ movel #-ENOSYS,%sp@(PT_OFF_D0)
jra ret_from_exception
do_trace:
- movel #-ENOSYS,%sp@(PT_D0) /* needed for strace*/
+ movel #-ENOSYS,%sp@(PT_OFF_D0) /* needed for strace*/
subql #4,%sp
SAVE_SWITCH_STACK
jbsr syscall_trace
RESTORE_SWITCH_STACK
addql #4,%sp
- movel %sp@(PT_ORIG_D0),%d1
+ movel %sp@(PT_OFF_ORIG_D0),%d1
movel #-ENOSYS,%d0
cmpl #NR_syscalls,%d1
jcc 1f
@@ -53,7 +53,7 @@ do_trace:
lea sys_call_table, %a0
jbsr %a0@(%d1)
-1: movel %d0,%sp@(PT_D0) /* save the return value */
+1: movel %d0,%sp@(PT_OFF_D0) /* save the return value */
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
jbsr syscall_trace
@@ -79,10 +79,10 @@ ENTRY(system_call)
lea sys_call_table,%a0
movel %a0@(%d0), %a0
jbsr %a0@
- movel %d0,%sp@(PT_D0) /* save the return value*/
+ movel %d0,%sp@(PT_OFF_D0) /* save the return value*/
ret_from_exception:
- btst #5,%sp@(PT_SR) /* check if returning to kernel*/
+ btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel*/
jeq Luser_return /* if so, skip resched, signals*/
Lkernel_return:
@@ -124,7 +124,7 @@ Lreturn:
*/
inthandler:
SAVE_ALL
- movew %sp@(PT_VECTOR), %d0
+ movew %sp@(PT_OFF_VECTOR), %d0
and.l #0x3ff, %d0
lsr.l #0x02, %d0
@@ -139,7 +139,7 @@ ret_from_interrupt:
2:
RESTORE_ALL
1:
- moveb %sp@(PT_SR), %d0
+ moveb %sp@(PT_OFF_SR), %d0
and #7, %d0
jhi 2b
/* check if we need to do software interrupts */
diff --git a/arch/m68knommu/platform/coldfire/entry.S b/arch/m68knommu/platform/coldfire/entry.S
index 3b471c0da24a..dd7d591f70ea 100644
--- a/arch/m68knommu/platform/coldfire/entry.S
+++ b/arch/m68knommu/platform/coldfire/entry.S
@@ -81,11 +81,11 @@ ENTRY(system_call)
movel %d3,%a0
jbsr %a0@
- movel %d0,%sp@(PT_D0) /* save the return value */
+ movel %d0,%sp@(PT_OFF_D0) /* save the return value */
jra ret_from_exception
1:
- movel #-ENOSYS,%d2 /* strace needs -ENOSYS in PT_D0 */
- movel %d2,PT_D0(%sp) /* on syscall entry */
+ movel #-ENOSYS,%d2 /* strace needs -ENOSYS in PT_OFF_D0 */
+ movel %d2,PT_OFF_D0(%sp) /* on syscall entry */
subql #4,%sp
SAVE_SWITCH_STACK
jbsr syscall_trace
@@ -93,7 +93,7 @@ ENTRY(system_call)
addql #4,%sp
movel %d3,%a0
jbsr %a0@
- movel %d0,%sp@(PT_D0) /* save the return value */
+ movel %d0,%sp@(PT_OFF_D0) /* save the return value */
subql #4,%sp /* dummy return address */
SAVE_SWITCH_STACK
jbsr syscall_trace
@@ -104,7 +104,7 @@ ret_from_signal:
ret_from_exception:
move #0x2700,%sr /* disable intrs */
- btst #5,%sp@(PT_SR) /* check if returning to kernel */
+ btst #5,%sp@(PT_OFF_SR) /* check if returning to kernel */
jeq Luser_return /* if so, skip resched, signals */
#ifdef CONFIG_PREEMPT
@@ -142,8 +142,8 @@ Luser_return:
Lreturn:
move #0x2700,%sr /* disable intrs */
movel sw_usp,%a0 /* get usp */
- movel %sp@(PT_PC),%a0@- /* copy exception program counter */
- movel %sp@(PT_FORMATVEC),%a0@-/* copy exception format/vector/sr */
+ movel %sp@(PT_OFF_PC),%a0@- /* copy exception program counter */
+ movel %sp@(PT_OFF_FORMATVEC),%a0@- /* copy exception format/vector/sr */
moveml %sp@,%d1-%d5/%a0-%a2
lea %sp@(32),%sp /* space for 8 regs */
movel %sp@+,%d0
@@ -181,9 +181,9 @@ Lsignal_return:
ENTRY(inthandler)
SAVE_ALL
moveq #-1,%d0
- movel %d0,%sp@(PT_ORIG_D0)
+ movel %d0,%sp@(PT_OFF_ORIG_D0)
- movew %sp@(PT_FORMATVEC),%d0 /* put exception # in d0 */
+ movew %sp@(PT_OFF_FORMATVEC),%d0 /* put exception # in d0 */
andl #0x03fc,%d0 /* mask out vector only */
movel %sp,%sp@- /* push regs arg */
@@ -203,7 +203,7 @@ ENTRY(inthandler)
ENTRY(fasthandler)
SAVE_LOCAL
- movew %sp@(PT_FORMATVEC),%d0
+ movew %sp@(PT_OFF_FORMATVEC),%d0
andl #0x03fc,%d0 /* mask out vector only */
movel %sp,%sp@- /* push regs arg */
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/kernel/entry.S b/arch/microblaze/kernel/entry.S
index acc1f05d1e2c..e3ecb36dd554 100644
--- a/arch/microblaze/kernel/entry.S
+++ b/arch/microblaze/kernel/entry.S
@@ -592,6 +592,8 @@ C_ENTRY(full_exception_trap):
nop
mfs r7, rfsr; /* save FSR */
nop
+ mts rfsr, r0; /* Clear sticky fsr */
+ nop
la r12, r0, full_exception
set_vms;
rtbd r12, 0;
diff --git a/arch/microblaze/kernel/hw_exception_handler.S b/arch/microblaze/kernel/hw_exception_handler.S
index 6b0288ebccd6..2b86c03aa841 100644
--- a/arch/microblaze/kernel/hw_exception_handler.S
+++ b/arch/microblaze/kernel/hw_exception_handler.S
@@ -384,7 +384,7 @@ handle_other_ex: /* Handle Other exceptions here */
addk r8, r17, r0; /* Load exception address */
bralid r15, full_exception; /* Branch to the handler */
nop;
- mts r0, rfsr; /* Clear sticky fsr */
+ mts rfsr, r0; /* Clear sticky fsr */
nop
/*
diff --git a/arch/microblaze/kernel/process.c b/arch/microblaze/kernel/process.c
index 4201c743cc9f..c592d475b3d8 100644
--- a/arch/microblaze/kernel/process.c
+++ b/arch/microblaze/kernel/process.c
@@ -235,7 +235,9 @@ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp)
regs->pc = pc;
regs->r1 = usp;
regs->pt_mode = 0;
+#ifdef CONFIG_MMU
regs->msr |= MSR_UMS;
+#endif
}
#ifdef CONFIG_MMU
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/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/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/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/Kconfig b/arch/parisc/Kconfig
index f388dc68f605..524d9352f17e 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -18,6 +18,7 @@ config PARISC
select BUG
select HAVE_PERF_EVENTS
select GENERIC_ATOMIC64 if !64BIT
+ select HAVE_ARCH_TRACEHOOK
help
The PA-RISC microprocessor is designed by Hewlett-Packard and used
in many of their workstations & servers (HP9000 700 and 800 series,
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/fixmap.h b/arch/parisc/include/asm/fixmap.h
index de3fe3a18229..6fec4d4a1a18 100644
--- a/arch/parisc/include/asm/fixmap.h
+++ b/arch/parisc/include/asm/fixmap.h
@@ -21,9 +21,9 @@
#define KERNEL_MAP_END (TMPALIAS_MAP_START)
#ifndef __ASSEMBLY__
-extern void *vmalloc_start;
+extern void *parisc_vmalloc_start;
#define PCXL_DMA_MAP_SIZE (8*1024*1024)
-#define VMALLOC_START ((unsigned long)vmalloc_start)
+#define VMALLOC_START ((unsigned long)parisc_vmalloc_start)
#define VMALLOC_END (KERNEL_MAP_END)
#endif /*__ASSEMBLY__*/
diff --git a/arch/parisc/include/asm/hardirq.h b/arch/parisc/include/asm/hardirq.h
index ce93133d5112..0d68184a76cb 100644
--- a/arch/parisc/include/asm/hardirq.h
+++ b/arch/parisc/include/asm/hardirq.h
@@ -1,29 +1,11 @@
/* hardirq.h: PA-RISC hard IRQ support.
*
* Copyright (C) 2001 Matthew Wilcox <matthew@wil.cx>
- *
- * The locking is really quite interesting. There's a cpu-local
- * count of how many interrupts are being handled, and a global
- * lock. An interrupt can only be serviced if the global lock
- * is free. You can't be sure no more interrupts are being
- * serviced until you've acquired the lock and then checked
- * all the per-cpu interrupt counts are all zero. It's a specialised
- * br_lock, and that's exactly how Sparc does it. We don't because
- * it's more locking for us. This way is lock-free in the interrupt path.
*/
#ifndef _PARISC_HARDIRQ_H
#define _PARISC_HARDIRQ_H
-#include <linux/threads.h>
-#include <linux/irq.h>
-
-typedef struct {
- unsigned long __softirq_pending; /* set_bit is used on this */
-} ____cacheline_aligned irq_cpustat_t;
-
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
-
-void ack_bad_irq(unsigned int irq);
+#include <asm-generic/hardirq.h>
#endif /* _PARISC_HARDIRQ_H */
diff --git a/arch/parisc/include/asm/ptrace.h b/arch/parisc/include/asm/ptrace.h
index 302f68dc889c..aead40b16dd8 100644
--- a/arch/parisc/include/asm/ptrace.h
+++ b/arch/parisc/include/asm/ptrace.h
@@ -59,8 +59,11 @@ void user_enable_block_step(struct task_struct *task);
#define user_mode(regs) (((regs)->iaoq[0] & 3) ? 1 : 0)
#define user_space(regs) (((regs)->iasq[1] != 0) ? 1 : 0)
#define instruction_pointer(regs) ((regs)->iaoq[0] & ~3)
+#define user_stack_pointer(regs) ((regs)->gr[30])
unsigned long profile_pc(struct pt_regs *);
extern void show_regs(struct pt_regs *);
-#endif
+
+
+#endif /* __KERNEL__ */
#endif
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/include/asm/syscall.h b/arch/parisc/include/asm/syscall.h
new file mode 100644
index 000000000000..8bdfd2c8c39f
--- /dev/null
+++ b/arch/parisc/include/asm/syscall.h
@@ -0,0 +1,40 @@
+/* syscall.h */
+
+#ifndef _ASM_PARISC_SYSCALL_H_
+#define _ASM_PARISC_SYSCALL_H_
+
+#include <linux/err.h>
+#include <asm/ptrace.h>
+
+static inline long syscall_get_nr(struct task_struct *tsk,
+ struct pt_regs *regs)
+{
+ return regs->gr[20];
+}
+
+static inline void syscall_get_arguments(struct task_struct *tsk,
+ struct pt_regs *regs, unsigned int i,
+ unsigned int n, unsigned long *args)
+{
+ BUG_ON(i);
+
+ switch (n) {
+ case 6:
+ args[5] = regs->gr[21];
+ case 5:
+ args[4] = regs->gr[22];
+ case 4:
+ args[3] = regs->gr[23];
+ case 3:
+ args[2] = regs->gr[24];
+ case 2:
+ args[1] = regs->gr[25];
+ case 1:
+ args[0] = regs->gr[26];
+ break;
+ default:
+ BUG();
+ }
+}
+
+#endif /*_ASM_PARISC_SYSCALL_H_*/
diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h
index ac775a76bff7..7ecc1039cfed 100644
--- a/arch/parisc/include/asm/thread_info.h
+++ b/arch/parisc/include/asm/thread_info.h
@@ -32,6 +32,11 @@ struct thread_info {
#define init_thread_info (init_thread_union.thread_info)
#define init_stack (init_thread_union.stack)
+/* how to get the thread information struct from C */
+#define current_thread_info() ((struct thread_info *)mfctl(30))
+
+#endif /* !__ASSEMBLY */
+
/* thread information allocation */
#define THREAD_SIZE_ORDER 2
@@ -40,11 +45,6 @@ struct thread_info {
#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
#define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER)
-/* how to get the thread information struct from C */
-#define current_thread_info() ((struct thread_info *)mfctl(30))
-
-#endif /* !__ASSEMBLY */
-
#define PREEMPT_ACTIVE_BIT 28
#define PREEMPT_ACTIVE (1 << PREEMPT_ACTIVE_BIT)
@@ -60,6 +60,8 @@ struct thread_info {
#define TIF_RESTORE_SIGMASK 6 /* restore saved signal mask */
#define TIF_FREEZE 7 /* is freezing for suspend */
#define TIF_NOTIFY_RESUME 8 /* callback before returning to user */
+#define TIF_SINGLESTEP 9 /* single stepping? */
+#define TIF_BLOCKSTEP 10 /* branch stepping? */
#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
@@ -69,6 +71,8 @@ struct thread_info {
#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_FREEZE (1 << TIF_FREEZE)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
+#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
+#define _TIF_BLOCKSTEP (1 << TIF_BLOCKSTEP)
#define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | \
_TIF_NEED_RESCHED | _TIF_RESTORE_SIGMASK)
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
index 699cf8ef2118..fcd3c707bf12 100644
--- a/arch/parisc/kernel/asm-offsets.c
+++ b/arch/parisc/kernel/asm-offsets.c
@@ -270,8 +270,8 @@ int main(void)
DEFINE(DTLB_OFF_COUNT, offsetof(struct pdc_cache_info, dt_off_count));
DEFINE(DTLB_LOOP, offsetof(struct pdc_cache_info, dt_loop));
BLANK();
- DEFINE(PA_BLOCKSTEP_BIT, 31-PT_BLOCKSTEP_BIT);
- DEFINE(PA_SINGLESTEP_BIT, 31-PT_SINGLESTEP_BIT);
+ DEFINE(TIF_BLOCKSTEP_PA_BIT, 31-TIF_BLOCKSTEP);
+ DEFINE(TIF_SINGLESTEP_PA_BIT, 31-TIF_SINGLESTEP);
BLANK();
DEFINE(ASM_PMD_SHIFT, PMD_SHIFT);
DEFINE(ASM_PGDIR_SHIFT, PGDIR_SHIFT);
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 8c4712b74dc1..3a44f7f704fa 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -2047,12 +2047,13 @@ syscall_do_signal:
b,n syscall_check_sig
syscall_restore:
- /* Are we being ptraced? */
LDREG TI_TASK-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1
- ldw TASK_PTRACE(%r1), %r19
- bb,< %r19,31,syscall_restore_rfi
- nop
+ /* Are we being ptraced? */
+ ldw TASK_FLAGS(%r1),%r19
+ ldi (_TIF_SINGLESTEP|_TIF_BLOCKSTEP),%r2
+ and,COND(=) %r19,%r2,%r0
+ b,n syscall_restore_rfi
ldo TASK_PT_FR31(%r1),%r19 /* reload fpregs */
rest_fp %r19
@@ -2113,16 +2114,16 @@ syscall_restore_rfi:
ldi 0x0b,%r20 /* Create new PSW */
depi -1,13,1,%r20 /* C, Q, D, and I bits */
- /* The values of PA_SINGLESTEP_BIT and PA_BLOCKSTEP_BIT are
- * set in include/linux/ptrace.h and converted to PA bitmap
+ /* The values of SINGLESTEP_BIT and BLOCKSTEP_BIT are
+ * set in thread_info.h and converted to PA bitmap
* numbers in asm-offsets.c */
- /* if ((%r19.PA_SINGLESTEP_BIT)) { %r20.27=1} */
- extru,= %r19,PA_SINGLESTEP_BIT,1,%r0
+ /* if ((%r19.SINGLESTEP_BIT)) { %r20.27=1} */
+ extru,= %r19,TIF_SINGLESTEP_PA_BIT,1,%r0
depi -1,27,1,%r20 /* R bit */
- /* if ((%r19.PA_BLOCKSTEP_BIT)) { %r20.7=1} */
- extru,= %r19,PA_BLOCKSTEP_BIT,1,%r0
+ /* if ((%r19.BLOCKSTEP_BIT)) { %r20.7=1} */
+ extru,= %r19,TIF_BLOCKSTEP_PA_BIT,1,%r0
depi -1,7,1,%r20 /* T bit */
STREG %r20,TASK_PT_PSW(%r1)
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index 330f536a9324..2e7610cb33d5 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -423,8 +423,3 @@ void __init init_IRQ(void)
set_eiem(cpu_eiem); /* EIEM : enable all external intr */
}
-
-void ack_bad_irq(unsigned int irq)
-{
- printk(KERN_WARNING "unexpected IRQ %d\n", irq);
-}
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index 61ee0eec4e69..212074653df7 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -893,7 +893,7 @@ int module_finalize(const Elf_Ehdr *hdr,
* ourselves */
for (i = 1; i < hdr->e_shnum; i++) {
if(sechdrs[i].sh_type == SHT_SYMTAB
- && (sechdrs[i].sh_type & SHF_ALLOC)) {
+ && (sechdrs[i].sh_flags & SHF_ALLOC)) {
int strindex = sechdrs[i].sh_link;
/* FIXME: AWFUL HACK
* The cast is to drop the const from
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index 927db3668b6f..c4f49e45129d 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -13,6 +13,7 @@
#include <linux/smp.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
+#include <linux/tracehook.h>
#include <linux/user.h>
#include <linux/personality.h>
#include <linux/security.h>
@@ -35,7 +36,8 @@
*/
void ptrace_disable(struct task_struct *task)
{
- task->ptrace &= ~(PT_SINGLESTEP|PT_BLOCKSTEP);
+ clear_tsk_thread_flag(task, TIF_SINGLESTEP);
+ clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
/* make sure the trap bits are not set */
pa_psw(task)->r = 0;
@@ -55,8 +57,8 @@ void user_disable_single_step(struct task_struct *task)
void user_enable_single_step(struct task_struct *task)
{
- task->ptrace &= ~PT_BLOCKSTEP;
- task->ptrace |= PT_SINGLESTEP;
+ clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
+ set_tsk_thread_flag(task, TIF_SINGLESTEP);
if (pa_psw(task)->n) {
struct siginfo si;
@@ -98,8 +100,8 @@ void user_enable_single_step(struct task_struct *task)
void user_enable_block_step(struct task_struct *task)
{
- task->ptrace &= ~PT_SINGLESTEP;
- task->ptrace |= PT_BLOCKSTEP;
+ clear_tsk_thread_flag(task, TIF_SINGLESTEP);
+ set_tsk_thread_flag(task, TIF_BLOCKSTEP);
/* Enable taken branch trap. */
pa_psw(task)->r = 0;
@@ -263,22 +265,20 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
}
#endif
+long do_syscall_trace_enter(struct pt_regs *regs)
+{
+ if (test_thread_flag(TIF_SYSCALL_TRACE) &&
+ tracehook_report_syscall_entry(regs))
+ return -1L;
+
+ return regs->gr[20];
+}
-void syscall_trace(void)
+void do_syscall_trace_exit(struct pt_regs *regs)
{
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
- if (!(current->ptrace & PT_PTRACED))
- return;
- ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
- ? 0x80 : 0));
- /*
- * this isn't the same as continuing with a signal, but it will do
- * for normal use. strace only continues with a signal if the
- * stopping signal is not SIGTRAP. -brl
- */
- if (current->exit_code) {
- send_sig(current->exit_code, current, 1);
- current->exit_code = 0;
- }
+ int stepping = test_thread_flag(TIF_SINGLESTEP) ||
+ test_thread_flag(TIF_BLOCKSTEP);
+
+ if (stepping || test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(regs, stepping);
}
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 8eb3c63c407a..e8467e4aa8d1 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -21,6 +21,7 @@
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/ptrace.h>
+#include <linux/tracehook.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/compat.h>
@@ -34,7 +35,6 @@
#include <asm/asm-offsets.h>
#ifdef CONFIG_COMPAT
-#include <linux/compat.h>
#include "signal32.h"
#endif
@@ -468,6 +468,9 @@ handle_signal(unsigned long sig, siginfo_t *info, struct k_sigaction *ka,
sigaddset(&current->blocked,sig);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
+
+ tracehook_signal_handler(sig, info, ka, regs, 0);
+
return 1;
}
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
index 59fc1a43ec3e..f5f96021caa0 100644
--- a/arch/parisc/kernel/syscall.S
+++ b/arch/parisc/kernel/syscall.S
@@ -288,18 +288,23 @@ tracesys:
STREG %r18,PT_GR18(%r2)
/* Finished saving things for the debugger */
- ldil L%syscall_trace,%r1
+ copy %r2,%r26
+ ldil L%do_syscall_trace_enter,%r1
ldil L%tracesys_next,%r2
- be R%syscall_trace(%sr7,%r1)
+ be R%do_syscall_trace_enter(%sr7,%r1)
ldo R%tracesys_next(%r2),%r2
-tracesys_next:
+tracesys_next:
+ /* do_syscall_trace_enter either returned the syscallno, or -1L,
+ * so we skip restoring the PT_GR20 below, since we pulled it from
+ * task->thread.regs.gr[20] above.
+ */
+ copy %ret0,%r20
ldil L%sys_call_table,%r1
ldo R%sys_call_table(%r1), %r19
ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
LDREG TI_TASK(%r1), %r1
- LDREG TASK_PT_GR20(%r1), %r20
LDREG TASK_PT_GR26(%r1), %r26 /* Restore the users args */
LDREG TASK_PT_GR25(%r1), %r25
LDREG TASK_PT_GR24(%r1), %r24
@@ -336,7 +341,8 @@ tracesys_exit:
#ifdef CONFIG_64BIT
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- bl syscall_trace, %r2
+ ldo TASK_REGS(%r1),%r26
+ bl do_syscall_trace_exit,%r2
STREG %r28,TASK_PT_GR28(%r1) /* save return value now */
ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
LDREG TI_TASK(%r1), %r1
@@ -353,12 +359,12 @@ tracesys_exit:
tracesys_sigexit:
ldo -THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r1 /* get task ptr */
- LDREG 0(%r1), %r1
+ LDREG TI_TASK(%r1), %r1
#ifdef CONFIG_64BIT
ldo -16(%r30),%r29 /* Reference param save area */
#endif
- bl syscall_trace, %r2
- nop
+ bl do_syscall_trace_exit,%r2
+ ldo TASK_REGS(%r1),%r26
ldil L%syscall_exit_rfi,%r1
be,n R%syscall_exit_rfi(%sr7,%r1)
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index 775be2791bc2..fda4baa059b5 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -28,6 +28,7 @@
#include <asm/cache.h>
#include <asm/page.h>
#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
/* ld script to make hppa Linux kernel */
#ifndef CONFIG_64BIT
@@ -134,6 +135,15 @@ SECTIONS
__init_begin = .;
INIT_TEXT_SECTION(16384)
INIT_DATA_SECTION(16)
+ /* we have to discard exit text and such at runtime, not link time */
+ .exit.text :
+ {
+ EXIT_TEXT
+ }
+ .exit.data :
+ {
+ EXIT_DATA
+ }
PERCPU(PAGE_SIZE)
. = ALIGN(PAGE_SIZE);
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index d5aca31fddbb..13b6e3e59b99 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -434,8 +434,8 @@ void mark_rodata_ro(void)
#define SET_MAP_OFFSET(x) ((void *)(((unsigned long)(x) + VM_MAP_OFFSET) \
& ~(VM_MAP_OFFSET-1)))
-void *vmalloc_start __read_mostly;
-EXPORT_SYMBOL(vmalloc_start);
+void *parisc_vmalloc_start __read_mostly;
+EXPORT_SYMBOL(parisc_vmalloc_start);
#ifdef CONFIG_PA11
unsigned long pcxl_dma_start __read_mostly;
@@ -496,13 +496,14 @@ void __init mem_init(void)
#ifdef CONFIG_PA11
if (hppa_dma_ops == &pcxl_dma_ops) {
pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START);
- vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start + PCXL_DMA_MAP_SIZE);
+ parisc_vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start
+ + PCXL_DMA_MAP_SIZE);
} else {
pcxl_dma_start = 0;
- vmalloc_start = SET_MAP_OFFSET(MAP_START);
+ parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START);
}
#else
- vmalloc_start = SET_MAP_OFFSET(MAP_START);
+ parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START);
#endif
printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
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/firmware.h b/arch/powerpc/include/asm/firmware.h
index 3a179827528d..20778a405d7a 100644
--- a/arch/powerpc/include/asm/firmware.h
+++ b/arch/powerpc/include/asm/firmware.h
@@ -37,7 +37,7 @@
#define FW_FEATURE_VIO ASM_CONST(0x0000000000004000)
#define FW_FEATURE_RDMA ASM_CONST(0x0000000000008000)
#define FW_FEATURE_LLAN ASM_CONST(0x0000000000010000)
-#define FW_FEATURE_BULK ASM_CONST(0x0000000000020000)
+#define FW_FEATURE_BULK_REMOVE ASM_CONST(0x0000000000020000)
#define FW_FEATURE_XDABR ASM_CONST(0x0000000000040000)
#define FW_FEATURE_MULTITCE ASM_CONST(0x0000000000080000)
#define FW_FEATURE_SPLPAR ASM_CONST(0x0000000000100000)
@@ -45,8 +45,7 @@
#define FW_FEATURE_LPAR ASM_CONST(0x0000000000400000)
#define FW_FEATURE_PS3_LV1 ASM_CONST(0x0000000000800000)
#define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000)
-#define FW_FEATURE_BULK_REMOVE ASM_CONST(0x0000000002000000)
-#define FW_FEATURE_CMO ASM_CONST(0x0000000004000000)
+#define FW_FEATURE_CMO ASM_CONST(0x0000000002000000)
#ifndef __ASSEMBLY__
@@ -58,8 +57,9 @@ enum {
FW_FEATURE_PERF | FW_FEATURE_DUMP | FW_FEATURE_INTERRUPT |
FW_FEATURE_MIGRATE | FW_FEATURE_PERFMON | FW_FEATURE_CRQ |
FW_FEATURE_VIO | FW_FEATURE_RDMA | FW_FEATURE_LLAN |
- FW_FEATURE_BULK | FW_FEATURE_XDABR | FW_FEATURE_MULTITCE |
- FW_FEATURE_SPLPAR | FW_FEATURE_LPAR | FW_FEATURE_CMO,
+ FW_FEATURE_BULK_REMOVE | FW_FEATURE_XDABR |
+ FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR |
+ FW_FEATURE_CMO,
FW_FEATURE_PSERIES_ALWAYS = 0,
FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR,
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/cputable.c b/arch/powerpc/kernel/cputable.c
index 0b9c9135922e..03c862b6a9c4 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -711,6 +711,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
.cpu_setup = __setup_cpu_750,
.machine_check = machine_check_generic,
.platform = "ppc750",
+ .oprofile_cpu_type = "ppc/750",
+ .oprofile_type = PPC_OPROFILE_G4,
},
{ /* 745/755 */
.pvr_mask = 0xfffff000,
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 900e0eea0099..f9fd54bfcc84 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -1038,8 +1038,7 @@ _GLOBAL(mod_return_to_handler)
* We are in a module using the module's TOC.
* Switch to our TOC to run inside the core kernel.
*/
- LOAD_REG_IMMEDIATE(r4,ftrace_return_to_handler)
- ld r2, 8(r4)
+ ld r2, PACATOC(r13)
bl .ftrace_return_to_handler
nop
diff --git a/arch/powerpc/kernel/kgdb.c b/arch/powerpc/kernel/kgdb.c
index fe8f71dd0b3f..641c74bb8e27 100644
--- a/arch/powerpc/kernel/kgdb.c
+++ b/arch/powerpc/kernel/kgdb.c
@@ -282,12 +282,6 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
{
unsigned long *ptr = gdb_regs;
int reg;
-#ifdef CONFIG_SPE
- union {
- u32 v32[2];
- u64 v64;
- } acc;
-#endif
for (reg = 0; reg < 32; reg++)
UNPACK64(regs->gpr[reg], ptr);
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
index bb8209e34931..e8dfdbd9327a 100644
--- a/arch/powerpc/kernel/pci-common.c
+++ b/arch/powerpc/kernel/pci-common.c
@@ -1190,7 +1190,7 @@ EXPORT_SYMBOL(pcibios_align_resource);
* Reparent resource children of pr that conflict with res
* under res, and make res replace those children.
*/
-static int __init reparent_resources(struct resource *parent,
+static int reparent_resources(struct resource *parent,
struct resource *res)
{
struct resource *p, **pp;
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 1168c5f440ab..2ec1eaed19ca 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -1016,9 +1016,13 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
int curr_frame = current->curr_ret_stack;
extern void return_to_handler(void);
- unsigned long addr = (unsigned long)return_to_handler;
+ unsigned long rth = (unsigned long)return_to_handler;
+ unsigned long mrth = -1;
#ifdef CONFIG_PPC64
- addr = *(unsigned long*)addr;
+ extern void mod_return_to_handler(void);
+ rth = *(unsigned long *)rth;
+ mrth = (unsigned long)mod_return_to_handler;
+ mrth = *(unsigned long *)mrth;
#endif
#endif
@@ -1044,7 +1048,7 @@ void show_stack(struct task_struct *tsk, unsigned long *stack)
if (!firstframe || ip != lr) {
printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip);
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
- if (ip == addr && curr_frame >= 0) {
+ if ((ip == rth || ip == mrth) && curr_frame >= 0) {
printk(" (%pS)",
(void *)current->ret_stack[curr_frame].ret);
curr_frame--;
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index f56429362a12..27735a7ac12b 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -236,6 +236,7 @@ SECTIONS
READ_MOSTLY_DATA(L1_CACHE_BYTES)
}
+ . = ALIGN(PAGE_SIZE);
.data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
NOSAVE_DATA
}
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/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index bc44dc4b5c67..95ce35581696 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -72,19 +72,17 @@ _GLOBAL(slb_miss_kernel_load_vmemmap)
1:
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
- /* vmalloc/ioremap mapping encoding bits, the "li" instructions below
- * will be patched by the kernel at boot
+ /* vmalloc mapping gets the encoding from the PACA as the mapping
+ * can be demoted from 64K -> 4K dynamically on some machines
*/
-BEGIN_FTR_SECTION
- /* check whether this is in vmalloc or ioremap space */
clrldi r11,r10,48
cmpldi r11,(VMALLOC_SIZE >> 28) - 1
bgt 5f
lhz r11,PACAVMALLOCSLLP(r13)
b 6f
5:
-END_FTR_SECTION_IFCLR(CPU_FTR_CI_LARGE_PAGE)
-_GLOBAL(slb_miss_kernel_load_io)
+ /* IO mapping */
+ _GLOBAL(slb_miss_kernel_load_io)
li r11,0
6:
BEGIN_FTR_SECTION
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/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/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index aca5741ddc67..a86c34b3bb84 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -365,7 +365,7 @@ static int axon_msi_probe(struct of_device *device,
printk(KERN_ERR
"axon_msi: couldn't parse dcr properties on %s\n",
dn->full_name);
- goto out;
+ goto out_free_msic;
}
msic->dcr_host = dcr_map(dn, dcr_base, dcr_len);
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/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/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index 21226b74c9b2..414ca9849f23 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -540,8 +540,11 @@ static struct pmac_i2c_host_kw *__init kw_i2c_host_init(struct device_node *np)
/* Make sure IRQ is disabled */
kw_write_reg(reg_ier, 0);
- /* Request chip interrupt */
- if (request_irq(host->irq, kw_i2c_irq, 0, "keywest i2c", host))
+ /* Request chip interrupt. We set IRQF_TIMER because we don't
+ * want that interrupt disabled between the 2 passes of driver
+ * suspend or we'll have issues running the pfuncs
+ */
+ if (request_irq(host->irq, kw_i2c_irq, IRQF_TIMER, "keywest i2c", host))
host->irq = NO_IRQ;
printk(KERN_INFO "KeyWest i2c @0x%08x irq %d %s\n",
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 5a707da3f5c2..0a14d8cd314f 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -51,11 +51,10 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = {
{FW_FEATURE_VIO, "hcall-vio"},
{FW_FEATURE_RDMA, "hcall-rdma"},
{FW_FEATURE_LLAN, "hcall-lLAN"},
- {FW_FEATURE_BULK, "hcall-bulk"},
+ {FW_FEATURE_BULK_REMOVE, "hcall-bulk"},
{FW_FEATURE_XDABR, "hcall-xdabr"},
{FW_FEATURE_MULTITCE, "hcall-multi-tce"},
{FW_FEATURE_SPLPAR, "hcall-splpar"},
- {FW_FEATURE_BULK_REMOVE, "hcall-bulk"},
};
/* Build up the firmware features bitmask using the contents of
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_diag.c b/arch/s390/hypfs/hypfs_diag.c
index 704dd396257b..77df726180ba 100644
--- a/arch/s390/hypfs/hypfs_diag.c
+++ b/arch/s390/hypfs/hypfs_diag.c
@@ -438,7 +438,7 @@ static int diag204_probe(void)
}
if (diag204((unsigned long)SUBC_STIB6 |
(unsigned long)INFO_EXT, pages, buf) >= 0) {
- diag204_store_sc = SUBC_STIB7;
+ diag204_store_sc = SUBC_STIB6;
diag204_info_type = INFO_EXT;
goto out;
}
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/delay.h b/arch/s390/include/asm/delay.h
index a356c958e260..8a096b83f51f 100644
--- a/arch/s390/include/asm/delay.h
+++ b/arch/s390/include/asm/delay.h
@@ -14,10 +14,11 @@
#ifndef _S390_DELAY_H
#define _S390_DELAY_H
-extern void __udelay(unsigned long usecs);
-extern void udelay_simple(unsigned long usecs);
+extern void __udelay(unsigned long long usecs);
+extern void udelay_simple(unsigned long long usecs);
extern void __delay(unsigned long loops);
-#define udelay(n) __udelay(n)
+#define udelay(n) __udelay((unsigned long long) (n))
+#define mdelay(n) __udelay((unsigned long long) (n) * 1000)
#endif /* defined(_S390_DELAY_H) */
diff --git a/arch/s390/include/asm/elf.h b/arch/s390/include/asm/elf.h
index 74d0bbb7d955..e885442c1dfe 100644
--- a/arch/s390/include/asm/elf.h
+++ b/arch/s390/include/asm/elf.h
@@ -92,6 +92,18 @@
/* Keep this the last entry. */
#define R_390_NUM 61
+/* Bits present in AT_HWCAP. */
+#define HWCAP_S390_ESAN3 1
+#define HWCAP_S390_ZARCH 2
+#define HWCAP_S390_STFLE 4
+#define HWCAP_S390_MSA 8
+#define HWCAP_S390_LDISP 16
+#define HWCAP_S390_EIMM 32
+#define HWCAP_S390_DFP 64
+#define HWCAP_S390_HPAGE 128
+#define HWCAP_S390_ETF3EH 256
+#define HWCAP_S390_HIGH_GPRS 512
+
/*
* These are used to set parameters in the core dumps.
*/
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/ptrace.h b/arch/s390/include/asm/ptrace.h
index 539263fc9ab9..95dcf183a28d 100644
--- a/arch/s390/include/asm/ptrace.h
+++ b/arch/s390/include/asm/ptrace.h
@@ -311,6 +311,10 @@ typedef struct
__u32 orig_gpr2;
} s390_compat_regs;
+typedef struct
+{
+ __u32 gprs_high[NUM_GPRS];
+} s390_compat_regs_high;
#ifdef __KERNEL__
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/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/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/include/asm/ucontext.h b/arch/s390/include/asm/ucontext.h
index d69bec0b03f5..cfb874e66c9a 100644
--- a/arch/s390/include/asm/ucontext.h
+++ b/arch/s390/include/asm/ucontext.h
@@ -9,6 +9,21 @@
#ifndef _ASM_S390_UCONTEXT_H
#define _ASM_S390_UCONTEXT_H
+#define UC_EXTENDED 0x00000001
+
+#ifndef __s390x__
+
+struct ucontext_extended {
+ unsigned long uc_flags;
+ struct ucontext *uc_link;
+ stack_t uc_stack;
+ _sigregs uc_mcontext;
+ unsigned long uc_sigmask[2];
+ unsigned long uc_gprs_high[16];
+};
+
+#endif
+
struct ucontext {
unsigned long uc_flags;
struct ucontext *uc_link;
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c
index b537cb0e9b55..eee999853a7c 100644
--- a/arch/s390/kernel/compat_signal.c
+++ b/arch/s390/kernel/compat_signal.c
@@ -39,6 +39,7 @@ typedef struct
struct sigcontext32 sc;
_sigregs32 sregs;
int signo;
+ __u32 gprs_high[NUM_GPRS];
__u8 retcode[S390_SYSCALL_SIZE];
} sigframe32;
@@ -48,6 +49,7 @@ typedef struct
__u8 retcode[S390_SYSCALL_SIZE];
compat_siginfo_t info;
struct ucontext32 uc;
+ __u32 gprs_high[NUM_GPRS];
} rt_sigframe32;
int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
@@ -344,6 +346,30 @@ static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs)
return 0;
}
+static int save_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
+{
+ __u32 gprs_high[NUM_GPRS];
+ int i;
+
+ for (i = 0; i < NUM_GPRS; i++)
+ gprs_high[i] = regs->gprs[i] >> 32;
+
+ return __copy_to_user(uregs, &gprs_high, sizeof(gprs_high));
+}
+
+static int restore_sigregs_gprs_high(struct pt_regs *regs, __u32 __user *uregs)
+{
+ __u32 gprs_high[NUM_GPRS];
+ int err, i;
+
+ err = __copy_from_user(&gprs_high, uregs, sizeof(gprs_high));
+ if (err)
+ return err;
+ for (i = 0; i < NUM_GPRS; i++)
+ *(__u32 *)&regs->gprs[i] = gprs_high[i];
+ return 0;
+}
+
asmlinkage long sys32_sigreturn(void)
{
struct pt_regs *regs = task_pt_regs(current);
@@ -363,6 +389,8 @@ asmlinkage long sys32_sigreturn(void)
if (restore_sigregs32(regs, &frame->sregs))
goto badframe;
+ if (restore_sigregs_gprs_high(regs, frame->gprs_high))
+ goto badframe;
return regs->gprs[2];
@@ -394,6 +422,8 @@ asmlinkage long sys32_rt_sigreturn(void)
if (restore_sigregs32(regs, &frame->uc.uc_mcontext))
goto badframe;
+ if (restore_sigregs_gprs_high(regs, frame->gprs_high))
+ goto badframe;
err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp);
st.ss_sp = compat_ptr(ss_sp);
@@ -474,6 +504,8 @@ static int setup_frame32(int sig, struct k_sigaction *ka,
if (save_sigregs32(regs, &frame->sregs))
goto give_sigsegv;
+ if (save_sigregs_gprs_high(regs, frame->gprs_high))
+ goto give_sigsegv;
if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs))
goto give_sigsegv;
@@ -529,13 +561,14 @@ static int setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info,
goto give_sigsegv;
/* Create the ucontext. */
- err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(UC_EXTENDED, &frame->uc.uc_flags);
err |= __put_user(0, &frame->uc.uc_link);
err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
err |= __put_user(sas_ss_flags(regs->gprs[15]),
&frame->uc.uc_stack.ss_flags);
err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= save_sigregs32(regs, &frame->uc.uc_mcontext);
+ err |= save_sigregs_gprs_high(regs, frame->gprs_high);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
goto give_sigsegv;
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 682fb69dba21..cbd9901dc0f8 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -409,7 +409,7 @@ sys32_munmap_wrapper:
.globl sys32_truncate_wrapper
sys32_truncate_wrapper:
llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # unsigned long
+ lgfr %r3,%r3 # long
jg sys_truncate # branch to system call
.globl sys32_ftruncate_wrapper
diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c
index 57bdcb1e3cdf..f5fe34dd821b 100644
--- a/arch/s390/kernel/ftrace.c
+++ b/arch/s390/kernel/ftrace.c
@@ -185,9 +185,6 @@ unsigned long prepare_ftrace_return(unsigned long ip, unsigned long parent)
{
struct ftrace_graph_ent trace;
- /* Nmi's are currently unsupported. */
- if (unlikely(in_nmi()))
- goto out;
if (unlikely(atomic_read(&current->tracing_graph_pause)))
goto out;
if (ftrace_push_return_trace(parent, ip, &trace.depth, 0) == -EBUSY)
diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
index ab2e3ed28abc..639380a0c45c 100644
--- a/arch/s390/kernel/module.c
+++ b/arch/s390/kernel/module.c
@@ -55,6 +55,8 @@ void *module_alloc(unsigned long size)
/* Free memory returned from module_alloc */
void module_free(struct module *mod, void *module_region)
{
+ vfree(mod->arch.syminfo);
+ mod->arch.syminfo = NULL;
vfree(module_region);
}
@@ -402,6 +404,7 @@ int module_finalize(const Elf_Ehdr *hdr,
struct module *me)
{
vfree(me->arch.syminfo);
+ me->arch.syminfo = NULL;
return module_bug_finalize(hdr, sechdrs, me);
}
diff --git a/arch/s390/kernel/processor.c b/arch/s390/kernel/processor.c
index 802c8ab247f3..0729f36c2fe3 100644
--- a/arch/s390/kernel/processor.c
+++ b/arch/s390/kernel/processor.c
@@ -31,9 +31,9 @@ void __cpuinit print_cpu_info(void)
static int show_cpuinfo(struct seq_file *m, void *v)
{
- static const char *hwcap_str[9] = {
+ static const char *hwcap_str[10] = {
"esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
- "edat", "etf3eh"
+ "edat", "etf3eh", "highgprs"
};
struct _lowcore *lc;
unsigned long n = (unsigned long) v - 1;
@@ -48,7 +48,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
num_online_cpus(), loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ))%100);
seq_puts(m, "features\t: ");
- for (i = 0; i < 9; i++)
+ for (i = 0; i < 10; i++)
if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
seq_printf(m, "%s ", hwcap_str[i]);
seq_puts(m, "\n");
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index a8738676b26c..653c6a178740 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -57,6 +57,7 @@
enum s390_regset {
REGSET_GENERAL,
REGSET_FP,
+ REGSET_GENERAL_EXTENDED,
};
static void
@@ -879,6 +880,67 @@ static int s390_compat_regs_set(struct task_struct *target,
return rc;
}
+static int s390_compat_regs_high_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ compat_ulong_t *gprs_high;
+
+ gprs_high = (compat_ulong_t *)
+ &task_pt_regs(target)->gprs[pos / sizeof(compat_ulong_t)];
+ if (kbuf) {
+ compat_ulong_t *k = kbuf;
+ while (count > 0) {
+ *k++ = *gprs_high;
+ gprs_high += 2;
+ count -= sizeof(*k);
+ }
+ } else {
+ compat_ulong_t __user *u = ubuf;
+ while (count > 0) {
+ if (__put_user(*gprs_high, u++))
+ return -EFAULT;
+ gprs_high += 2;
+ count -= sizeof(*u);
+ }
+ }
+ return 0;
+}
+
+static int s390_compat_regs_high_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ compat_ulong_t *gprs_high;
+ int rc = 0;
+
+ gprs_high = (compat_ulong_t *)
+ &task_pt_regs(target)->gprs[pos / sizeof(compat_ulong_t)];
+ if (kbuf) {
+ const compat_ulong_t *k = kbuf;
+ while (count > 0) {
+ *gprs_high = *k++;
+ *gprs_high += 2;
+ count -= sizeof(*k);
+ }
+ } else {
+ const compat_ulong_t __user *u = ubuf;
+ while (count > 0 && !rc) {
+ unsigned long word;
+ rc = __get_user(word, u++);
+ if (rc)
+ break;
+ *gprs_high = word;
+ *gprs_high += 2;
+ count -= sizeof(*u);
+ }
+ }
+
+ return rc;
+}
+
static const struct user_regset s390_compat_regsets[] = {
[REGSET_GENERAL] = {
.core_note_type = NT_PRSTATUS,
@@ -896,6 +958,14 @@ static const struct user_regset s390_compat_regsets[] = {
.get = s390_fpregs_get,
.set = s390_fpregs_set,
},
+ [REGSET_GENERAL_EXTENDED] = {
+ .core_note_type = NT_PRXSTATUS,
+ .n = sizeof(s390_compat_regs_high) / sizeof(compat_long_t),
+ .size = sizeof(compat_long_t),
+ .align = sizeof(compat_long_t),
+ .get = s390_compat_regs_high_get,
+ .set = s390_compat_regs_high_set,
+ },
};
static const struct user_regset_view user_s390_compat_view = {
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 9ed13a1ed376..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 =
@@ -729,7 +733,7 @@ static void __init setup_hwcaps(void)
if ((facility_list & (1UL << (31 - 22)))
&& (facility_list & (1UL << (31 - 30))))
- elf_hwcap |= 1UL << 8;
+ elf_hwcap |= HWCAP_S390_ETF3EH;
/*
* Check for additional facilities with store-facility-list-extended.
@@ -748,11 +752,20 @@ static void __init setup_hwcaps(void)
__stfle(&facility_list_extended, 1) > 0) {
if ((facility_list_extended & (1ULL << (63 - 42)))
&& (facility_list_extended & (1ULL << (63 - 44))))
- elf_hwcap |= 1UL << 6;
+ elf_hwcap |= HWCAP_S390_DFP;
}
+ /*
+ * Huge page support HWCAP_S390_HPAGE is bit 7.
+ */
if (MACHINE_HAS_HPAGE)
- elf_hwcap |= 1UL << 7;
+ elf_hwcap |= HWCAP_S390_HPAGE;
+
+ /*
+ * 64-bit register support for 31-bit processes
+ * HWCAP_S390_HIGH_GPRS is bit 9.
+ */
+ elf_hwcap |= HWCAP_S390_HIGH_GPRS;
switch (S390_lowcore.cpu_id.machine) {
case 0x9672:
diff --git a/arch/s390/kernel/swsusp_asm64.S b/arch/s390/kernel/swsusp_asm64.S
index fe927d0bc20b..7c8653e27db6 100644
--- a/arch/s390/kernel/swsusp_asm64.S
+++ b/arch/s390/kernel/swsusp_asm64.S
@@ -43,7 +43,7 @@ swsusp_arch_suspend:
lghi %r1,0x1000
/* Save CPU address */
- stap __LC_CPU_ADDRESS(%r1)
+ stap __LC_CPU_ADDRESS(%r0)
/* Store registers */
mvc 0x318(4,%r1),__SF_EMPTY(%r15) /* move prefix to lowcore */
@@ -69,8 +69,21 @@ swsusp_arch_suspend:
stmg %r0,%r15,0x280(%r1) /* store general registers */
stpt 0x328(%r1) /* store timer */
+ stck __SF_EMPTY(%r15) /* store clock */
stckc 0x330(%r1) /* store clock comparator */
+ /* Update cputime accounting before going to sleep */
+ lg %r0,__LC_LAST_UPDATE_TIMER
+ slg %r0,0x328(%r1)
+ alg %r0,__LC_SYSTEM_TIMER
+ stg %r0,__LC_SYSTEM_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),0x328(%r1)
+ lg %r0,__LC_LAST_UPDATE_CLOCK
+ slg %r0,__SF_EMPTY(%r15)
+ alg %r0,__LC_STEAL_TIMER
+ stg %r0,__LC_STEAL_TIMER
+ mvc __LC_LAST_UPDATE_CLOCK(8),__SF_EMPTY(%r15)
+
/* Activate DAT */
stosm __SF_EMPTY(%r15),0x04
@@ -159,8 +172,7 @@ pgm_check_entry:
larl %r1,.Lresume_cpu /* Resume CPU address: r2 */
stap 0(%r1)
llgh %r2,0(%r1)
- lghi %r3,0x1000
- llgh %r1,__LC_CPU_ADDRESS(%r3) /* Suspend CPU address: r1 */
+ llgh %r1,__LC_CPU_ADDRESS(%r0) /* Suspend CPU address: r1 */
cgr %r1,%r2
je restore_registers /* r1 = r2 -> nothing to do */
larl %r4,.Lrestart_suspend_psw /* Set new restart PSW */
@@ -200,8 +212,11 @@ restart_suspend:
restore_registers:
/* Restore registers */
- lghi %r13,0x1000 /* %r1 = pointer to save arae */
+ lghi %r13,0x1000 /* %r1 = pointer to save area */
+ /* Ignore time spent in suspended state. */
+ llgf %r1,0x318(%r13)
+ stck __LC_LAST_UPDATE_CLOCK(%r1)
spt 0x328(%r13) /* reprogram timer */
//sckc 0x330(%r13) /* set clock comparator */
@@ -229,9 +244,6 @@ restore_registers:
/* Load old stack */
lg %r15,0x2f8(%r13)
- /* Pointer to save area */
- lghi %r13,0x1000
-
/* Restore prefix register */
spx 0x318(%r13)
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index 45a3e9a7ae21..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 */
@@ -247,6 +248,13 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
}
/*
+ * Put vDSO base into mm struct. We need to do this before calling
+ * install_special_mapping or the perf counter mmap tracking code
+ * will fail to recognise it as a vDSO (since arch_vma_name fails).
+ */
+ current->mm->context.vdso_base = vdso_base;
+
+ /*
* our vma flags don't have VM_WRITE so by default, the process
* isn't allowed to write those pages.
* gdb can break that with ptrace interface, and thus trigger COW
@@ -267,14 +275,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
VM_ALWAYSDUMP,
vdso_pagelist);
if (rc)
- goto out_up;
-
- /* Put vDSO base into mm struct */
- current->mm->context.vdso_base = vdso_base;
-
- up_write(&mm->mmap_sem);
- return 0;
-
+ current->mm->context.vdso_base = 0;
out_up:
up_write(&mm->mmap_sem);
return rc;
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index bc15ef93e656..a68ac10213b2 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -51,6 +51,7 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
_eshared = .; /* End of shareable data */
+ _sdata = .; /* Start of data section */
EXCEPTION_TABLE(16) :data
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/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index ec5eee7c25d8..06cce8285ba0 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -58,7 +58,7 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu,
int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code);
int kvm_s390_inject_sigp_stop(struct kvm_vcpu *vcpu, int action);
-static inline int kvm_s390_vcpu_get_memsize(struct kvm_vcpu *vcpu)
+static inline long kvm_s390_vcpu_get_memsize(struct kvm_vcpu *vcpu)
{
return vcpu->arch.sie_block->gmslm
- vcpu->arch.sie_block->gmsor
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index 97c1eca83cc2..752b362bf651 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -25,13 +25,13 @@ void __delay(unsigned long loops)
asm volatile("0: brct %0,0b" : : "d" ((loops/2) + 1));
}
-static void __udelay_disabled(unsigned long usecs)
+static void __udelay_disabled(unsigned long long usecs)
{
unsigned long mask, cr0, cr0_saved;
u64 clock_saved;
clock_saved = local_tick_disable();
- set_clock_comparator(get_clock() + ((u64) usecs << 12));
+ set_clock_comparator(get_clock() + (usecs << 12));
__ctl_store(cr0_saved, 0, 0);
cr0 = (cr0_saved & 0xffff00e0) | 0x00000800;
__ctl_load(cr0 , 0, 0);
@@ -46,20 +46,25 @@ static void __udelay_disabled(unsigned long usecs)
set_clock_comparator(S390_lowcore.clock_comparator);
}
-static void __udelay_enabled(unsigned long usecs)
+static void __udelay_enabled(unsigned long long usecs)
{
unsigned long mask;
- u64 end, time;
+ u64 clock_saved;
+ u64 end;
mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT | PSW_MASK_IO;
- end = get_clock() + ((u64) usecs << 12);
+ end = get_clock() + (usecs << 12);
do {
- time = end < S390_lowcore.clock_comparator ?
- end : S390_lowcore.clock_comparator;
- set_clock_comparator(time);
+ clock_saved = 0;
+ if (end < S390_lowcore.clock_comparator) {
+ clock_saved = local_tick_disable();
+ set_clock_comparator(end);
+ }
trace_hardirqs_on();
__load_psw_mask(mask);
local_irq_disable();
+ if (clock_saved)
+ local_tick_enable(clock_saved);
} while (get_clock() < end);
set_clock_comparator(S390_lowcore.clock_comparator);
}
@@ -67,7 +72,7 @@ static void __udelay_enabled(unsigned long usecs)
/*
* Waits for 'usecs' microseconds using the TOD clock comparator.
*/
-void __udelay(unsigned long usecs)
+void __udelay(unsigned long long usecs)
{
unsigned long flags;
@@ -101,11 +106,11 @@ EXPORT_SYMBOL(__udelay);
* Simple udelay variant. To be used on startup and reboot
* when the interrupt handler isn't working.
*/
-void udelay_simple(unsigned long usecs)
+void udelay_simple(unsigned long long usecs)
{
u64 end;
- end = get_clock() + ((u64) usecs << 12);
+ end = get_clock() + (usecs << 12);
while (get_clock() < end)
cpu_relax();
}
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
index 3f15aaf54855..60455f104ea3 100644
--- a/arch/s390/lib/uaccess_mvcos.c
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -36,7 +36,7 @@ static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
tmp1 = -4096UL;
asm volatile(
"0: .insn ss,0xc80000000000,0(%0,%2),0(%1),0\n"
- " jz 7f\n"
+ "9: jz 7f\n"
"1:"ALR" %0,%3\n"
" "SLR" %1,%3\n"
" "SLR" %2,%3\n"
@@ -47,7 +47,7 @@ static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
" "CLR" %0,%4\n" /* copy crosses next page boundary? */
" jnh 4f\n"
"3: .insn ss,0xc80000000000,0(%4,%2),0(%1),0\n"
- " "SLR" %0,%4\n"
+ "10:"SLR" %0,%4\n"
" "ALR" %2,%4\n"
"4:"LHI" %4,-1\n"
" "ALR" %4,%0\n" /* copy remaining size, subtract 1 */
@@ -61,7 +61,7 @@ static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
" j 8f\n"
"7:"SLR" %0,%0\n"
"8: \n"
- EX_TABLE(0b,2b) EX_TABLE(3b,4b)
+ EX_TABLE(0b,2b) EX_TABLE(3b,4b) EX_TABLE(9b,2b) EX_TABLE(10b,4b)
: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
: "d" (reg0) : "cc", "memory");
return size;
@@ -82,7 +82,7 @@ static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
tmp1 = -4096UL;
asm volatile(
"0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
- " jz 4f\n"
+ "6: jz 4f\n"
"1:"ALR" %0,%3\n"
" "SLR" %1,%3\n"
" "SLR" %2,%3\n"
@@ -93,11 +93,11 @@ static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
" "CLR" %0,%4\n" /* copy crosses next page boundary? */
" jnh 5f\n"
"3: .insn ss,0xc80000000000,0(%4,%1),0(%2),0\n"
- " "SLR" %0,%4\n"
+ "7:"SLR" %0,%4\n"
" j 5f\n"
"4:"SLR" %0,%0\n"
"5: \n"
- EX_TABLE(0b,2b) EX_TABLE(3b,5b)
+ EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b)
: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
: "d" (reg0) : "cc", "memory");
return size;
@@ -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/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index d2ffbadb51a7..07deaeee14c8 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -36,12 +36,12 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
tmp1 = -256UL;
asm volatile(
"0: mvcp 0(%0,%2),0(%1),%3\n"
- " jz 8f\n"
+ "10:jz 8f\n"
"1:"ALR" %0,%3\n"
" la %1,256(%1)\n"
" la %2,256(%2)\n"
"2: mvcp 0(%0,%2),0(%1),%3\n"
- " jnz 1b\n"
+ "11:jnz 1b\n"
" j 8f\n"
"3: la %4,255(%1)\n" /* %4 = ptr + 255 */
" "LHI" %3,-4096\n"
@@ -50,7 +50,7 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
" "CLR" %0,%4\n" /* copy crosses next page boundary? */
" jnh 5f\n"
"4: mvcp 0(%4,%2),0(%1),%3\n"
- " "SLR" %0,%4\n"
+ "12:"SLR" %0,%4\n"
" "ALR" %2,%4\n"
"5:"LHI" %4,-1\n"
" "ALR" %4,%0\n" /* copy remaining size, subtract 1 */
@@ -65,6 +65,7 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
"8:"SLR" %0,%0\n"
"9: \n"
EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,5b)
+ EX_TABLE(10b,3b) EX_TABLE(11b,3b) EX_TABLE(12b,5b)
: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
: : "cc", "memory");
return size;
@@ -85,12 +86,12 @@ size_t copy_to_user_std(size_t size, void __user *ptr, const void *x)
tmp1 = -256UL;
asm volatile(
"0: mvcs 0(%0,%1),0(%2),%3\n"
- " jz 5f\n"
+ "7: jz 5f\n"
"1:"ALR" %0,%3\n"
" la %1,256(%1)\n"
" la %2,256(%2)\n"
"2: mvcs 0(%0,%1),0(%2),%3\n"
- " jnz 1b\n"
+ "8: jnz 1b\n"
" j 5f\n"
"3: la %4,255(%1)\n" /* %4 = ptr + 255 */
" "LHI" %3,-4096\n"
@@ -99,11 +100,12 @@ size_t copy_to_user_std(size_t size, void __user *ptr, const void *x)
" "CLR" %0,%4\n" /* copy crosses next page boundary? */
" jnh 6f\n"
"4: mvcs 0(%4,%1),0(%2),%3\n"
- " "SLR" %0,%4\n"
+ "9:"SLR" %0,%4\n"
" j 6f\n"
"5:"SLR" %0,%0\n"
"6: \n"
EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
+ EX_TABLE(7b,3b) EX_TABLE(8b,3b) EX_TABLE(9b,6b)
: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
: : "cc", "memory");
return size;
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 c60bfb309ce6..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 */
@@ -279,7 +279,10 @@ int s390_enable_sie(void)
/* lets check if we are allowed to replace the mm */
task_lock(tsk);
if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 ||
- tsk->mm != tsk->active_mm || !hlist_empty(&tsk->mm->ioctx_list)) {
+#ifdef CONFIG_AIO
+ !hlist_empty(&tsk->mm->ioctx_list) ||
+#endif
+ tsk->mm != tsk->active_mm) {
task_unlock(tsk);
return -EINVAL;
}
@@ -295,7 +298,10 @@ int s390_enable_sie(void)
/* Now lets check again if something happened */
task_lock(tsk);
if (!tsk->mm || atomic_read(&tsk->mm->mm_users) > 1 ||
- tsk->mm != tsk->active_mm || !hlist_empty(&tsk->mm->ioctx_list)) {
+#ifdef CONFIG_AIO
+ !hlist_empty(&tsk->mm->ioctx_list) ||
+#endif
+ tsk->mm != tsk->active_mm) {
mmput(mm);
task_unlock(tsk);
return -EINVAL;
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index b940424f8ccc..5260fb55ab7f 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -38,6 +38,7 @@ config SUPERH32
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
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index fc51a918b31a..d1dc2f415a27 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -201,10 +201,7 @@ libs-$(CONFIG_SUPERH64) := arch/sh/lib64/ $(libs-y)
BOOT_TARGETS = uImage uImage.bz2 uImage.gz uImage.lzma uImage.srec \
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)
@@ -229,5 +227,3 @@ define archhelp
@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-magicpanelr2.c b/arch/sh/boards/board-magicpanelr2.c
index 0a37c8bfc959..99ffc5f1c0dd 100644
--- a/arch/sh/boards/board-magicpanelr2.c
+++ b/arch/sh/boards/board-magicpanelr2.c
@@ -205,8 +205,6 @@ static void __init setup_port_multiplexing(void)
static void __init mpr2_setup(char **cmdline_p)
{
- __set_io_port_base(0xa0000000);
-
/* set Pin Select Register A:
* /PCC_CD1, /PCC_CD2, PCC_BVD1, PCC_BVD2,
* /IOIS16, IRQ4, IRQ5, USB1d_SUSPEND
diff --git a/arch/sh/boards/mach-dreamcast/setup.c b/arch/sh/boards/mach-dreamcast/setup.c
index ebe99227d4e6..a4b7402d6176 100644
--- a/arch/sh/boards/mach-dreamcast/setup.c
+++ b/arch/sh/boards/mach-dreamcast/setup.c
@@ -42,8 +42,6 @@ static void __init dreamcast_setup(char **cmdline_p)
/* Acknowledge any previous events */
/* XXX */
- __set_io_port_base(0xa0000000);
-
/* Assign all virtual IRQs to the System ASIC int. handler */
for (i = HW_EVENT_IRQ_BASE; i < HW_EVENT_IRQ_MAX; i++)
set_irq_chip_and_handler(i, &systemasic_int,
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 5f9881e16e2f..3b1ceb46fa54 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/usb/r8a66597.h>
#include <linux/i2c.h>
+#include <linux/i2c/tsc2007.h>
#include <linux/input.h>
#include <video/sh_mobile_lcdc.h>
#include <media/sh_mobile_ceu.h>
@@ -38,6 +39,20 @@
* 0x1800_0000 MFI 16bit
*/
+/* SWITCH
+ *------------------------------
+ * DS2[1] = FlashROM write protect ON : write protect
+ * OFF : No write protect
+ * DS2[2] = RMII / TS, SCIF ON : RMII
+ * OFF : TS, SCIF3
+ * DS2[3] = Camera / Video ON : Camera
+ * OFF : NTSC/PAL (IN)
+ * DS2[5] = NTSC_OUT Clock ON : On board OSC
+ * OFF : SH7724 DV_CLK
+ * DS2[6-7] = MMC / SD ON-OFF : SD
+ * OFF-ON : MMC
+ */
+
/* Heartbeat */
static unsigned char led_pos[] = { 0, 1, 2, 3 };
static struct heartbeat_data heartbeat_data = {
@@ -70,7 +85,7 @@ static struct mtd_partition nor_flash_partitions[] = {
.name = "boot loader",
.offset = 0,
.size = (5 * 1024 * 1024),
- .mask_flags = MTD_CAP_ROM,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
}, {
.name = "free-area",
.offset = MTDPART_OFS_APPEND,
@@ -376,6 +391,43 @@ static struct platform_device keysc_device = {
},
};
+/* TouchScreen */
+#define IRQ0 32
+static int ts_get_pendown_state(void)
+{
+ int val = 0;
+ gpio_free(GPIO_FN_INTC_IRQ0);
+ gpio_request(GPIO_PTZ0, NULL);
+ gpio_direction_input(GPIO_PTZ0);
+
+ val = gpio_get_value(GPIO_PTZ0);
+
+ gpio_free(GPIO_PTZ0);
+ gpio_request(GPIO_FN_INTC_IRQ0, NULL);
+
+ return val ? 0 : 1;
+}
+
+static int ts_init(void)
+{
+ gpio_request(GPIO_FN_INTC_IRQ0, NULL);
+ return 0;
+}
+
+struct tsc2007_platform_data tsc2007_info = {
+ .model = 2007,
+ .x_plate_ohms = 180,
+ .get_pendown_state = ts_get_pendown_state,
+ .init_platform_hw = ts_init,
+};
+
+static struct i2c_board_info ts_i2c_clients = {
+ I2C_BOARD_INFO("tsc2007", 0x48),
+ .type = "tsc2007",
+ .platform_data = &tsc2007_info,
+ .irq = IRQ0,
+};
+
static struct platform_device *ecovec_devices[] __initdata = {
&heartbeat_device,
&nor_flash_device,
@@ -460,6 +512,11 @@ static void __init sh_eth_init(void)
#define IODRIVEA 0xA405018A
static int __init arch_setup(void)
{
+ /* enable STATUS0, STATUS2 and PDSTATUS */
+ gpio_request(GPIO_FN_STATUS0, NULL);
+ gpio_request(GPIO_FN_STATUS2, NULL);
+ gpio_request(GPIO_FN_PDSTATUS, NULL);
+
/* enable SCIFA0 */
gpio_request(GPIO_FN_SCIF0_TXD, NULL);
gpio_request(GPIO_FN_SCIF0_RXD, NULL);
@@ -590,6 +647,10 @@ static int __init arch_setup(void)
*/
gpio_request(GPIO_PTF4, NULL);
gpio_direction_output(GPIO_PTF4, 1);
+
+ /* enable TouchScreen */
+ i2c_register_board_info(0, &ts_i2c_clients, 1);
+ set_irq_type(IRQ0, IRQ_TYPE_LEVEL_LOW);
}
/* enable CEU0 */
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index c08d33fe2104..ce01d6a953b8 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,131 @@ 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 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,
};
#define BSC_CS0BCR 0xfec10004
@@ -361,6 +483,23 @@ 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);
+
return platform_add_devices(kfr2r09_devices,
ARRAY_SIZE(kfr2r09_devices));
}
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/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/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/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/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/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/kernel/Makefile b/arch/sh/kernel/Makefile
index a2d0a40f3848..f8791203cfe3 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -9,8 +9,11 @@ ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_ftrace.o = -pg
endif
+CFLAGS_REMOVE_return_address.o = -pg
+
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 \
+ 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/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index 0151933e5253..bb407ef0b91e 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -152,8 +152,6 @@ call_do_page_fault:
mov.l 1f, r0
mov.l @r0, r6
- sti
-
mov.l 3f, r0
mov.l 4f, r1
mov r15, r4
diff --git a/arch/sh/kernel/cpu/sh4a/setup-shx3.c b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
index e848443deeb9..485330cf8549 100644
--- a/arch/sh/kernel/cpu/sh4a/setup-shx3.c
+++ b/arch/sh/kernel/cpu/sh4a/setup-shx3.c
@@ -268,7 +268,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 +295,7 @@ enum {
INTICI4, INTICI5, INTICI6, INTICI7,
/* interrupt groups */
- PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
+ IRL, PCII56789, SCIF0, SCIF1, SCIF2, SCIF3,
DMAC0, DMAC1,
};
@@ -344,6 +348,10 @@ 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),
@@ -419,14 +427,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/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/dwarf.c b/arch/sh/kernel/dwarf.c
index 03b3616c80a5..718286be6648 100644
--- a/arch/sh/kernel/dwarf.c
+++ b/arch/sh/kernel/dwarf.c
@@ -20,6 +20,7 @@
#include <linux/list.h>
#include <linux/mempool.h>
#include <linux/mm.h>
+#include <linux/elf.h>
#include <asm/dwarf.h>
#include <asm/unwinder.h>
#include <asm/sections.h>
@@ -529,7 +530,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 +559,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.
@@ -571,9 +583,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 +626,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 +659,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 +760,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 +772,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 +821,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 +846,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 +857,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,15 +889,15 @@ 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;
@@ -890,32 +905,12 @@ static int __init dwarf_unwinder_init(void)
unsigned long len;
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);
-
- dwarf_reg_cachep = kmem_cache_create("dwarf_regs",
- sizeof(struct dwarf_reg), 0,
- SLAB_PANIC | SLAB_HWCACHE_ALIGN | SLAB_NOTRACK, NULL);
+ entry = eh_frame_start;
- 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 +922,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 +934,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 +954,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 68d9223b145e..f0abd58c3a69 100644
--- a/arch/sh/kernel/entry-common.S
+++ b/arch/sh/kernel/entry-common.S
@@ -121,7 +121,7 @@ noresched:
ENTRY(resume_userspace)
! r8: current_thread_info
cli
- TRACE_IRQS_OfF
+ TRACE_IRQS_OFF
mov.l @(TI_FLAGS,r8), r0 ! current_thread_info->flags
tst #(_TIF_WORK_MASK & 0xff), r0
bt/s __restore_all
@@ -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 a3dcc6d5d253..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);
@@ -291,31 +435,48 @@ struct syscall_metadata *syscall_nr_to_meta(int nr)
return syscalls_metadata[nr];
}
-void arch_init_ftrace_syscalls(void)
+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;
+}
+
+static int __init arch_init_ftrace_syscalls(void)
{
int i;
struct syscall_metadata *meta;
unsigned long **psys_syscall_table = &sys_call_table;
- static atomic_t refs;
-
- if (atomic_inc_return(&refs) != 1)
- goto end;
syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) *
FTRACE_SYSCALL_MAX, GFP_KERNEL);
if (!syscalls_metadata) {
WARN_ON(1);
- return;
+ return -ENOMEM;
}
for (i = 0; i < FTRACE_SYSCALL_MAX; i++) {
meta = find_syscall_meta(psys_syscall_table[i]);
syscalls_metadata[i] = meta;
}
- return;
- /* Paranoid: avoid overflow */
-end:
- atomic_dec(&refs);
+ return 0;
}
+arch_initcall(arch_init_ftrace_syscalls);
#endif /* CONFIG_FTRACE_SYSCALLS */
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/io_generic.c b/arch/sh/kernel/io_generic.c
index 4ff507239286..b8fa6524760a 100644
--- a/arch/sh/kernel/io_generic.c
+++ b/arch/sh/kernel/io_generic.c
@@ -147,6 +147,9 @@ void generic_outsl(unsigned long port, const void *src, unsigned long count)
void __iomem *generic_ioport_map(unsigned long addr, unsigned int size)
{
+ if (PXSEG(addr) >= P1SEG)
+ return (void __iomem *)addr;
+
return (void __iomem *)(addr + generic_io_base);
}
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 7cb933ba4957..11c289ecc090 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -36,7 +36,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;
}
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 7ea2704ea033..de7cf5477d3f 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -49,7 +49,7 @@ 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))
+ if (image->start != __pa(image->start))
return -EINVAL; /* upgrade your kexec-tools */
return 0;
diff --git a/arch/sh/kernel/machvec.c b/arch/sh/kernel/machvec.c
index 548f6607fd0f..cbce639b108a 100644
--- a/arch/sh/kernel/machvec.c
+++ b/arch/sh/kernel/machvec.c
@@ -14,6 +14,7 @@
#include <linux/string.h>
#include <asm/machvec.h>
#include <asm/sections.h>
+#include <asm/addrspace.h>
#include <asm/setup.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -133,4 +134,6 @@ void __init sh_mv_setup(void)
if (!sh_mv.mv_nr_irqs)
sh_mv.mv_nr_irqs = NR_IRQS;
+
+ __set_io_port_base(P2SEG);
}
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/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 f9d44f8e0df6..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
@@ -549,6 +553,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
if (cpu == 0)
seq_printf(m, "machine\t\t: %s\n", get_system_type());
+ else
+ seq_printf(m, "\n");
seq_printf(m, "processor\t: %d\n", cpu);
seq_printf(m, "cpu family\t: %s\n", init_utsname()->machine);
diff --git a/arch/sh/kernel/sh_ksyms_32.c b/arch/sh/kernel/sh_ksyms_32.c
index 8dbe26b17c44..86c270428357 100644
--- a/arch/sh/kernel/sh_ksyms_32.c
+++ b/arch/sh/kernel/sh_ksyms_32.c
@@ -84,6 +84,7 @@ DECLARE_EXPORT(__movstrSI60);
DECLARE_EXPORT(__movstr_i4_even);
DECLARE_EXPORT(__movstr_i4_odd);
DECLARE_EXPORT(__movstrSI12_i4);
+DECLARE_EXPORT(__movmem);
DECLARE_EXPORT(__movmem_i4_even);
DECLARE_EXPORT(__movmem_i4_odd);
DECLARE_EXPORT(__movmemSI12_i4);
diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c
index 6729703547a1..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;
}
@@ -145,7 +146,7 @@ static inline int restore_sigcontext_fpu(struct sigcontext __user *sc)
{
struct task_struct *tsk = current;
- if (!(current_cpu_data.flags & CPU_HAS_FPU))
+ if (!(boot_cpu_data.flags & CPU_HAS_FPU))
return 0;
set_used_math();
@@ -158,7 +159,7 @@ static inline int save_sigcontext_fpu(struct sigcontext __user *sc,
{
struct task_struct *tsk = current;
- if (!(current_cpu_data.flags & CPU_HAS_FPU))
+ if (!(boot_cpu_data.flags & CPU_HAS_FPU))
return 0;
if (!used_math()) {
@@ -199,7 +200,7 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *r0_p
#undef COPY
#ifdef CONFIG_SH_FPU
- if (current_cpu_data.flags & CPU_HAS_FPU) {
+ if (boot_cpu_data.flags & CPU_HAS_FPU) {
int owned_fp;
struct task_struct *tsk = current;
@@ -472,6 +473,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
err |= __put_user(OR_R0_R0, &frame->retcode[6]);
err |= __put_user((__NR_rt_sigreturn), &frame->retcode[7]);
regs->pr = (unsigned long) frame->retcode;
+ flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode));
}
if (err)
@@ -497,8 +499,6 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
current->comm, task_pid_nr(current), frame, regs->pc, regs->pr);
- flush_icache_range(regs->pr, regs->pr + sizeof(frame->retcode));
-
return 0;
give_sigsegv:
@@ -591,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;
@@ -603,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));
@@ -632,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 442d8d47a41e..983e0792d5f3 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -35,6 +35,8 @@ static inline void __init smp_store_cpu_info(unsigned int cpu)
{
struct sh_cpuinfo *c = cpu_data + cpu;
+ memcpy(c, &boot_cpu_data, sizeof(struct sh_cpuinfo));
+
c->loops_per_jiffy = loops_per_jiffy;
}
@@ -120,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/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 69bb1652eccd..7a2ee3a6b8e7 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -25,6 +25,7 @@
#include <linux/kexec.h>
#include <linux/limits.h>
#include <linux/proc_fs.h>
+#include <linux/sysfs.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/fpu.h>
@@ -54,8 +55,8 @@ static unsigned long se_multi;
/* bitfield: 1: warn 2: fixup 4: signal -> combinations 2|4 && 1|2|4 are not
valid! */
static int se_usermode = 3;
-/* 0: no warning 1: print a warning message */
-static int se_kernmode_warn = 1;
+/* 0: no warning 1: print a warning message, disabled by default */
+static int se_kernmode_warn;
#ifdef CONFIG_PROC_FS
static const char *se_usermode_action[] = {
@@ -159,12 +160,12 @@ void die(const char * str, struct pt_regs * regs, long err)
oops_enter();
- console_verbose();
spin_lock_irq(&die_lock);
+ console_verbose();
bust_spinlocks(1);
printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
-
+ sysfs_printk_last_file();
print_modules();
show_regs(regs);
@@ -180,6 +181,7 @@ void die(const char * str, struct pt_regs * regs, long err)
bust_spinlocks(0);
add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock);
+ oops_exit();
if (kexec_should_crash(current))
crash_kexec(regs);
@@ -190,7 +192,6 @@ void die(const char * str, struct pt_regs * regs, long err)
if (panic_on_oops)
panic("Fatal exception");
- oops_exit();
do_exit(SIGSEGV);
}
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index 64dc1ad59801..b8a9032c74be 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
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 b2453bbef4cd..56dd55a1b13e 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,27 +25,18 @@
* 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,
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,
* signal handler code and kprobes code
*/
-static void sh4_flush_icache_range(void *args)
+static void __uses_jump_to_uncached sh4_flush_icache_range(void *args)
{
struct flusher_data *data = args;
unsigned long start, end;
@@ -95,16 +88,16 @@ static inline void flush_cache_4096(unsigned long start,
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);
+ virt_to_phys(phys), exec_offset);
local_irq_restore(flags);
}
@@ -123,12 +116,12 @@ 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;
+ n = boot_cpu_data.dcache.way_incr >> 12;
for (i = 0; i < n; i++, addr += 4096)
flush_cache_4096(addr, phys);
}
@@ -158,10 +151,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 +180,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 +197,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 +210,64 @@ 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;
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);
- }
+ address &= PAGE_MASK;
+ 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_4096(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,24 +300,10 @@ 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();
- }
}
/**
@@ -443,7 +357,7 @@ static void __flush_cache_4096(unsigned long addr, unsigned long phys,
* pointless nead-of-loop check for 0 iterations.
*/
do {
- ea = base_addr + PAGE_SIZE;
+ ea = base_addr + 4096;
a = base_addr;
p = phys;
@@ -463,245 +377,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 +384,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 2cadee2037ac..f527fb70fce6 100644
--- a/arch/sh/mm/cache-sh7705.c
+++ b/arch/sh/mm/cache-sh7705.c
@@ -78,7 +78,7 @@ static void sh7705_flush_icache_range(void *args)
/*
* Writeback&Invalidate the D-cache of the page
*/
-static void __flush_dcache_page(unsigned long phys)
+static void __uses_jump_to_uncached __flush_dcache_page(unsigned long phys)
{
unsigned long ways, waysize, addrstart;
unsigned long flags;
@@ -141,10 +141,10 @@ 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 sh7705_flush_cache_all(void *args)
+static void __uses_jump_to_uncached sh7705_flush_cache_all(void *args)
{
unsigned long flags;
diff --git a/arch/sh/mm/cache.c b/arch/sh/mm/cache.c
index 35c37b7f717a..e8810f7fc7ea 100644
--- a/arch/sh/mm/cache.c
+++ b/arch/sh/mm/cache.c
@@ -128,7 +128,7 @@ void __update_cache(struct vm_area_struct *vma,
return;
page = pfn_to_page(pfn);
- if (pfn_valid(pfn) && page_mapping(page)) {
+ if (pfn_valid(pfn)) {
int dirty = test_and_clear_bit(PG_dcache_dirty, &page->flags);
if (dirty) {
unsigned long addr = (unsigned long)page_address(page);
@@ -164,11 +164,17 @@ void flush_cache_all(void)
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);
}
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index e098ec158ddb..9a8403d9344b 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -85,7 +85,7 @@ 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..c8af6c5fa586 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -323,4 +323,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/ioremap_32.c b/arch/sh/mm/ioremap_32.c
index c3250614e3ae..a86eaa9d75a5 100644
--- a/arch/sh/mm/ioremap_32.c
+++ b/arch/sh/mm/ioremap_32.c
@@ -83,7 +83,7 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
*
* PMB entries are all pre-faulted.
*/
- if (unlikely(size >= 0x1000000)) {
+ if (unlikely(phys_addr >= P1SEG)) {
unsigned long mapped = pmb_remap(addr, phys_addr, size, flags);
if (likely(mapped)) {
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 b1a714a92b14..280f6a166035 100644
--- a/arch/sh/mm/pmb.c
+++ b/arch/sh/mm/pmb.c
@@ -33,28 +33,10 @@
#define NR_PMB_ENTRIES 16
-static struct kmem_cache *pmb_cache;
-static unsigned long pmb_map;
+static void __pmb_unmap(struct pmb_entry *);
-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 struct pmb_entry pmb_entry_list[NR_PMB_ENTRIES];
+static unsigned long pmb_map;
static inline unsigned long mk_pmb_entry(unsigned int entry)
{
@@ -71,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;
+
+ pmbe->vpn = 0;
+ pmbe->ppn = 0;
+ pmbe->flags = 0;
+ pmbe->entry = 0;
- kmem_cache_free(pmb_cache, pmbe);
+ 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
@@ -159,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();
@@ -200,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);
}
@@ -218,9 +171,10 @@ static struct {
long pmb_remap(unsigned long vaddr, unsigned long phys,
unsigned long size, unsigned long flags)
{
- struct pmb_entry *pmbp;
+ struct pmb_entry *pmbp, *pmbe;
unsigned long wanted;
int pmb_flags, i;
+ long err;
/* Convert typical pgprot value to the PMB equivalent */
if (flags & _PAGE_CACHABLE) {
@@ -236,22 +190,18 @@ long pmb_remap(unsigned long vaddr, unsigned long phys,
again:
for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) {
- struct pmb_entry *pmbe;
- int ret;
-
if (size < pmb_sizes[i].size)
continue;
- pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag);
- if (IS_ERR(pmbe))
- return PTR_ERR(pmbe);
-
- ret = set_pmb_entry(pmbe);
- if (ret != 0) {
- pmb_free(pmbe);
- return -EBUSY;
+ pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag,
+ PMB_NO_ENTRY);
+ if (IS_ERR(pmbe)) {
+ err = PTR_ERR(pmbe);
+ goto out;
}
+ set_pmb_entry(pmbe);
+
phys += pmb_sizes[i].size;
vaddr += pmb_sizes[i].size;
size -= pmb_sizes[i].size;
@@ -264,73 +214,99 @@ again:
pmbp->link = pmbe;
pmbp = pmbe;
+
+ /*
+ * Instead of trying smaller sizes on every iteration
+ * (even if we succeed in allocating space), try using
+ * pmb_sizes[i].size again.
+ */
+ i--;
}
if (size >= 0x1000000)
goto again;
return wanted - size;
+
+out:
+ if (pmbp)
+ __pmb_unmap(pmbp);
+
+ return err;
}
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;
- WARN_ON(!test_bit(pmbe->entry, &pmb_map));
+ __pmb_unmap(pmbe);
+}
+
+static void __pmb_unmap(struct pmb_entry *pmbe)
+{
+ BUG_ON(!test_bit(pmbe->entry, &pmb_map));
do {
struct pmb_entry *pmblink = 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;
pmb_free(pmblink);
} 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);
@@ -341,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)
{
@@ -409,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/Kconfig b/arch/sparc/Kconfig
index ac45aab741a5..05ef5380a687 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -26,6 +26,7 @@ config SPARC
select RTC_CLASS
select RTC_DRV_M48T59
select HAVE_PERF_EVENTS
+ select PERF_USE_VMALLOC
select HAVE_DMA_ATTRS
select HAVE_DMA_API_DEBUG
@@ -48,6 +49,7 @@ config SPARC64
select RTC_DRV_SUN4V
select RTC_DRV_STARFIRE
select HAVE_PERF_EVENTS
+ select PERF_USE_VMALLOC
config ARCH_DEFCONFIG
string
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/hardirq_32.h b/arch/sparc/include/asm/hardirq_32.h
index 4f63ed8df551..162007643cdc 100644
--- a/arch/sparc/include/asm/hardirq_32.h
+++ b/arch/sparc/include/asm/hardirq_32.h
@@ -7,17 +7,7 @@
#ifndef __SPARC_HARDIRQ_H
#define __SPARC_HARDIRQ_H
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/cache.h>
-
-/* entry.S is sensitive to the offsets of these fields */ /* XXX P3 Is it? */
-typedef struct {
- unsigned int __softirq_pending;
-} ____cacheline_aligned irq_cpustat_t;
-
-#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
-
#define HARDIRQ_BITS 8
+#include <asm-generic/hardirq.h>
#endif /* __SPARC_HARDIRQ_H */
diff --git a/arch/sparc/include/asm/irq_32.h b/arch/sparc/include/asm/irq_32.h
index ea43057d4763..cbf4801deaaf 100644
--- a/arch/sparc/include/asm/irq_32.h
+++ b/arch/sparc/include/asm/irq_32.h
@@ -6,10 +6,10 @@
#ifndef _SPARC_IRQ_H
#define _SPARC_IRQ_H
-#include <linux/interrupt.h>
-
#define NR_IRQS 16
+#include <linux/interrupt.h>
+
#define irq_canonicalize(irq) (irq)
extern void __init init_IRQ(void);
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/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index 0ff92fa22064..f3cb790fa2ae 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -41,8 +41,8 @@
#define LOW_OBP_ADDRESS _AC(0x00000000f0000000,UL)
#define HI_OBP_ADDRESS _AC(0x0000000100000000,UL)
#define VMALLOC_START _AC(0x0000000100000000,UL)
-#define VMALLOC_END _AC(0x0000000200000000,UL)
-#define VMEMMAP_BASE _AC(0x0000000200000000,UL)
+#define VMALLOC_END _AC(0x0000010000000000,UL)
+#define VMEMMAP_BASE _AC(0x0000010000000000,UL)
#define vmemmap ((struct page *)VMEMMAP_BASE)
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/ktlb.S b/arch/sparc/kernel/ktlb.S
index 3ea6e8cde8c5..1d361477d7d6 100644
--- a/arch/sparc/kernel/ktlb.S
+++ b/arch/sparc/kernel/ktlb.S
@@ -280,8 +280,8 @@ kvmap_dtlb_nonlinear:
#ifdef CONFIG_SPARSEMEM_VMEMMAP
/* Do not use the TSB for vmemmap. */
- mov (VMEMMAP_BASE >> 24), %g5
- sllx %g5, 24, %g5
+ mov (VMEMMAP_BASE >> 40), %g5
+ sllx %g5, 40, %g5
cmp %g4,%g5
bgeu,pn %xcc, kvmap_vmemmap
nop
@@ -293,8 +293,8 @@ kvmap_dtlb_tsbmiss:
sethi %hi(MODULES_VADDR), %g5
cmp %g4, %g5
blu,pn %xcc, kvmap_dtlb_longpath
- mov (VMALLOC_END >> 24), %g5
- sllx %g5, 24, %g5
+ mov (VMALLOC_END >> 40), %g5
+ sllx %g5, 40, %g5
cmp %g4, %g5
bgeu,pn %xcc, kvmap_dtlb_longpath
nop
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c
index adf5f273868a..cb3c72c45aab 100644
--- a/arch/sparc/kernel/ldc.c
+++ b/arch/sparc/kernel/ldc.c
@@ -1242,13 +1242,13 @@ int ldc_bind(struct ldc_channel *lp, const char *name)
snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name);
err = request_irq(lp->cfg.rx_irq, ldc_rx,
- IRQF_SAMPLE_RANDOM | IRQF_SHARED,
+ IRQF_SAMPLE_RANDOM | IRQF_DISABLED | IRQF_SHARED,
lp->rx_irq_name, lp);
if (err)
return err;
err = request_irq(lp->cfg.tx_irq, ldc_tx,
- IRQF_SAMPLE_RANDOM | IRQF_SHARED,
+ IRQF_SAMPLE_RANDOM | IRQF_DISABLED | IRQF_SHARED,
lp->tx_irq_name, lp);
if (err) {
free_irq(lp->cfg.rx_irq, lp);
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/perf_event.c b/arch/sparc/kernel/perf_event.c
index 2d6a1b10c81d..fa5936e1c3b9 100644
--- a/arch/sparc/kernel/perf_event.c
+++ b/arch/sparc/kernel/perf_event.c
@@ -56,7 +56,8 @@ struct cpu_hw_events {
struct perf_event *events[MAX_HWEVENTS];
unsigned long used_mask[BITS_TO_LONGS(MAX_HWEVENTS)];
unsigned long active_mask[BITS_TO_LONGS(MAX_HWEVENTS)];
- int enabled;
+ u64 pcr;
+ int enabled;
};
DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { .enabled = 1, };
@@ -68,8 +69,30 @@ struct perf_event_map {
#define PIC_LOWER 0x02
};
+static unsigned long perf_event_encode(const struct perf_event_map *pmap)
+{
+ return ((unsigned long) pmap->encoding << 16) | pmap->pic_mask;
+}
+
+static void perf_event_decode(unsigned long val, u16 *enc, u8 *msk)
+{
+ *msk = val & 0xff;
+ *enc = val >> 16;
+}
+
+#define C(x) PERF_COUNT_HW_CACHE_##x
+
+#define CACHE_OP_UNSUPPORTED 0xfffe
+#define CACHE_OP_NONSENSE 0xffff
+
+typedef struct perf_event_map cache_map_t
+ [PERF_COUNT_HW_CACHE_MAX]
+ [PERF_COUNT_HW_CACHE_OP_MAX]
+ [PERF_COUNT_HW_CACHE_RESULT_MAX];
+
struct sparc_pmu {
const struct perf_event_map *(*event_map)(int);
+ const cache_map_t *cache_map;
int max_events;
int upper_shift;
int lower_shift;
@@ -80,21 +103,109 @@ struct sparc_pmu {
int lower_nop;
};
-static const struct perf_event_map ultra3i_perfmon_event_map[] = {
+static const struct perf_event_map ultra3_perfmon_event_map[] = {
[PERF_COUNT_HW_CPU_CYCLES] = { 0x0000, PIC_UPPER | PIC_LOWER },
[PERF_COUNT_HW_INSTRUCTIONS] = { 0x0001, PIC_UPPER | PIC_LOWER },
[PERF_COUNT_HW_CACHE_REFERENCES] = { 0x0009, PIC_LOWER },
[PERF_COUNT_HW_CACHE_MISSES] = { 0x0009, PIC_UPPER },
};
-static const struct perf_event_map *ultra3i_event_map(int event_id)
+static const struct perf_event_map *ultra3_event_map(int event_id)
{
- return &ultra3i_perfmon_event_map[event_id];
+ return &ultra3_perfmon_event_map[event_id];
}
-static const struct sparc_pmu ultra3i_pmu = {
- .event_map = ultra3i_event_map,
- .max_events = ARRAY_SIZE(ultra3i_perfmon_event_map),
+static const cache_map_t ultra3_cache_map = {
+[C(L1D)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { 0x09, PIC_LOWER, },
+ [C(RESULT_MISS)] = { 0x09, PIC_UPPER, },
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = { 0x0a, PIC_LOWER },
+ [C(RESULT_MISS)] = { 0x0a, PIC_UPPER },
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(L1I)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { 0x09, PIC_LOWER, },
+ [C(RESULT_MISS)] = { 0x09, PIC_UPPER, },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_NONSENSE },
+ [ C(RESULT_MISS) ] = { CACHE_OP_NONSENSE },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(LL)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { 0x0c, PIC_LOWER, },
+ [C(RESULT_MISS)] = { 0x0c, PIC_UPPER, },
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = { 0x0c, PIC_LOWER },
+ [C(RESULT_MISS)] = { 0x0c, PIC_UPPER },
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(DTLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { 0x12, PIC_UPPER, },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(ITLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { 0x11, PIC_UPPER, },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(BPU)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+};
+
+static const struct sparc_pmu ultra3_pmu = {
+ .event_map = ultra3_event_map,
+ .cache_map = &ultra3_cache_map,
+ .max_events = ARRAY_SIZE(ultra3_perfmon_event_map),
.upper_shift = 11,
.lower_shift = 4,
.event_mask = 0x3f,
@@ -102,6 +213,121 @@ static const struct sparc_pmu ultra3i_pmu = {
.lower_nop = 0x14,
};
+/* Niagara1 is very limited. The upper PIC is hard-locked to count
+ * only instructions, so it is free running which creates all kinds of
+ * problems. Some hardware designs make one wonder if the creator
+ * even looked at how this stuff gets used by software.
+ */
+static const struct perf_event_map niagara1_perfmon_event_map[] = {
+ [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, PIC_UPPER },
+ [PERF_COUNT_HW_INSTRUCTIONS] = { 0x00, PIC_UPPER },
+ [PERF_COUNT_HW_CACHE_REFERENCES] = { 0, PIC_NONE },
+ [PERF_COUNT_HW_CACHE_MISSES] = { 0x03, PIC_LOWER },
+};
+
+static const struct perf_event_map *niagara1_event_map(int event_id)
+{
+ return &niagara1_perfmon_event_map[event_id];
+}
+
+static const cache_map_t niagara1_cache_map = {
+[C(L1D)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { 0x03, PIC_LOWER, },
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { 0x03, PIC_LOWER, },
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(L1I)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { 0x00, PIC_UPPER },
+ [C(RESULT_MISS)] = { 0x02, PIC_LOWER, },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_NONSENSE },
+ [ C(RESULT_MISS) ] = { CACHE_OP_NONSENSE },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(LL)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { 0x07, PIC_LOWER, },
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { 0x07, PIC_LOWER, },
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(DTLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { 0x05, PIC_LOWER, },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(ITLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { 0x04, PIC_LOWER, },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(BPU)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+};
+
+static const struct sparc_pmu niagara1_pmu = {
+ .event_map = niagara1_event_map,
+ .cache_map = &niagara1_cache_map,
+ .max_events = ARRAY_SIZE(niagara1_perfmon_event_map),
+ .upper_shift = 0,
+ .lower_shift = 4,
+ .event_mask = 0x7,
+ .upper_nop = 0x0,
+ .lower_nop = 0x0,
+};
+
static const struct perf_event_map niagara2_perfmon_event_map[] = {
[PERF_COUNT_HW_CPU_CYCLES] = { 0x02ff, PIC_UPPER | PIC_LOWER },
[PERF_COUNT_HW_INSTRUCTIONS] = { 0x02ff, PIC_UPPER | PIC_LOWER },
@@ -116,14 +342,102 @@ static const struct perf_event_map *niagara2_event_map(int event_id)
return &niagara2_perfmon_event_map[event_id];
}
+static const cache_map_t niagara2_cache_map = {
+[C(L1D)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { 0x0208, PIC_UPPER | PIC_LOWER, },
+ [C(RESULT_MISS)] = { 0x0302, PIC_UPPER | PIC_LOWER, },
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = { 0x0210, PIC_UPPER | PIC_LOWER, },
+ [C(RESULT_MISS)] = { 0x0302, PIC_UPPER | PIC_LOWER, },
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(L1I)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { 0x02ff, PIC_UPPER | PIC_LOWER, },
+ [C(RESULT_MISS)] = { 0x0301, PIC_UPPER | PIC_LOWER, },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_NONSENSE },
+ [ C(RESULT_MISS) ] = { CACHE_OP_NONSENSE },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(LL)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { 0x0208, PIC_UPPER | PIC_LOWER, },
+ [C(RESULT_MISS)] = { 0x0330, PIC_UPPER | PIC_LOWER, },
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = { 0x0210, PIC_UPPER | PIC_LOWER, },
+ [C(RESULT_MISS)] = { 0x0320, PIC_UPPER | PIC_LOWER, },
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(DTLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { 0x0b08, PIC_UPPER | PIC_LOWER, },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(ITLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { 0xb04, PIC_UPPER | PIC_LOWER, },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+[C(BPU)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = { CACHE_OP_UNSUPPORTED },
+ [C(RESULT_MISS)] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_WRITE) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+ [ C(OP_PREFETCH) ] = {
+ [ C(RESULT_ACCESS) ] = { CACHE_OP_UNSUPPORTED },
+ [ C(RESULT_MISS) ] = { CACHE_OP_UNSUPPORTED },
+ },
+},
+};
+
static const struct sparc_pmu niagara2_pmu = {
.event_map = niagara2_event_map,
+ .cache_map = &niagara2_cache_map,
.max_events = ARRAY_SIZE(niagara2_perfmon_event_map),
.upper_shift = 19,
.lower_shift = 6,
.event_mask = 0xfff,
.hv_bit = 0x8,
- .irq_bit = 0x03,
+ .irq_bit = 0x30,
.upper_nop = 0x220,
.lower_nop = 0x220,
};
@@ -151,23 +465,30 @@ static u64 nop_for_index(int idx)
sparc_pmu->lower_nop, idx);
}
-static inline void sparc_pmu_enable_event(struct hw_perf_event *hwc,
- int idx)
+static inline void sparc_pmu_enable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx)
{
u64 val, mask = mask_for_index(idx);
- val = pcr_ops->read();
- pcr_ops->write((val & ~mask) | hwc->config);
+ val = cpuc->pcr;
+ val &= ~mask;
+ val |= hwc->config;
+ cpuc->pcr = val;
+
+ pcr_ops->write(cpuc->pcr);
}
-static inline void sparc_pmu_disable_event(struct hw_perf_event *hwc,
- int idx)
+static inline void sparc_pmu_disable_event(struct cpu_hw_events *cpuc, struct hw_perf_event *hwc, int idx)
{
u64 mask = mask_for_index(idx);
u64 nop = nop_for_index(idx);
- u64 val = pcr_ops->read();
+ u64 val;
- pcr_ops->write((val & ~mask) | nop);
+ val = cpuc->pcr;
+ val &= ~mask;
+ val |= nop;
+ cpuc->pcr = val;
+
+ pcr_ops->write(cpuc->pcr);
}
void hw_perf_enable(void)
@@ -182,7 +503,7 @@ void hw_perf_enable(void)
cpuc->enabled = 1;
barrier();
- val = pcr_ops->read();
+ val = cpuc->pcr;
for (i = 0; i < MAX_HWEVENTS; i++) {
struct perf_event *cp = cpuc->events[i];
@@ -194,7 +515,9 @@ void hw_perf_enable(void)
val |= hwc->config_base;
}
- pcr_ops->write(val);
+ cpuc->pcr = val;
+
+ pcr_ops->write(cpuc->pcr);
}
void hw_perf_disable(void)
@@ -207,10 +530,12 @@ void hw_perf_disable(void)
cpuc->enabled = 0;
- val = pcr_ops->read();
+ val = cpuc->pcr;
val &= ~(PCR_UTRACE | PCR_STRACE |
sparc_pmu->hv_bit | sparc_pmu->irq_bit);
- pcr_ops->write(val);
+ cpuc->pcr = val;
+
+ pcr_ops->write(cpuc->pcr);
}
static u32 read_pmc(int idx)
@@ -242,7 +567,7 @@ static void write_pmc(int idx, u64 val)
}
static int sparc_perf_event_set_period(struct perf_event *event,
- struct hw_perf_event *hwc, int idx)
+ struct hw_perf_event *hwc, int idx)
{
s64 left = atomic64_read(&hwc->period_left);
s64 period = hwc->sample_period;
@@ -282,19 +607,19 @@ static int sparc_pmu_enable(struct perf_event *event)
if (test_and_set_bit(idx, cpuc->used_mask))
return -EAGAIN;
- sparc_pmu_disable_event(hwc, idx);
+ sparc_pmu_disable_event(cpuc, hwc, idx);
cpuc->events[idx] = event;
set_bit(idx, cpuc->active_mask);
sparc_perf_event_set_period(event, hwc, idx);
- sparc_pmu_enable_event(hwc, idx);
+ sparc_pmu_enable_event(cpuc, hwc, idx);
perf_event_update_userpage(event);
return 0;
}
static u64 sparc_perf_event_update(struct perf_event *event,
- struct hw_perf_event *hwc, int idx)
+ struct hw_perf_event *hwc, int idx)
{
int shift = 64 - 32;
u64 prev_raw_count, new_raw_count;
@@ -324,7 +649,7 @@ static void sparc_pmu_disable(struct perf_event *event)
int idx = hwc->idx;
clear_bit(idx, cpuc->active_mask);
- sparc_pmu_disable_event(hwc, idx);
+ sparc_pmu_disable_event(cpuc, hwc, idx);
barrier();
@@ -338,18 +663,29 @@ static void sparc_pmu_disable(struct perf_event *event)
static void sparc_pmu_read(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
+
sparc_perf_event_update(event, hwc, hwc->idx);
}
static void sparc_pmu_unthrottle(struct perf_event *event)
{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
struct hw_perf_event *hwc = &event->hw;
- sparc_pmu_enable_event(hwc, hwc->idx);
+
+ sparc_pmu_enable_event(cpuc, hwc, hwc->idx);
}
static atomic_t active_events = ATOMIC_INIT(0);
static DEFINE_MUTEX(pmc_grab_mutex);
+static void perf_stop_nmi_watchdog(void *unused)
+{
+ struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
+
+ stop_nmi_watchdog(NULL);
+ cpuc->pcr = pcr_ops->read();
+}
+
void perf_event_grab_pmc(void)
{
if (atomic_inc_not_zero(&active_events))
@@ -358,7 +694,7 @@ void perf_event_grab_pmc(void)
mutex_lock(&pmc_grab_mutex);
if (atomic_read(&active_events) == 0) {
if (atomic_read(&nmi_active) > 0) {
- on_each_cpu(stop_nmi_watchdog, NULL, 1);
+ on_each_cpu(perf_stop_nmi_watchdog, NULL, 1);
BUG_ON(atomic_read(&nmi_active) != 0);
}
atomic_inc(&active_events);
@@ -375,30 +711,160 @@ void perf_event_release_pmc(void)
}
}
+static const struct perf_event_map *sparc_map_cache_event(u64 config)
+{
+ unsigned int cache_type, cache_op, cache_result;
+ const struct perf_event_map *pmap;
+
+ if (!sparc_pmu->cache_map)
+ return ERR_PTR(-ENOENT);
+
+ cache_type = (config >> 0) & 0xff;
+ if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
+ return ERR_PTR(-EINVAL);
+
+ cache_op = (config >> 8) & 0xff;
+ if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
+ return ERR_PTR(-EINVAL);
+
+ cache_result = (config >> 16) & 0xff;
+ if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+ return ERR_PTR(-EINVAL);
+
+ pmap = &((*sparc_pmu->cache_map)[cache_type][cache_op][cache_result]);
+
+ if (pmap->encoding == CACHE_OP_UNSUPPORTED)
+ return ERR_PTR(-ENOENT);
+
+ if (pmap->encoding == CACHE_OP_NONSENSE)
+ return ERR_PTR(-EINVAL);
+
+ return pmap;
+}
+
static void hw_perf_event_destroy(struct perf_event *event)
{
perf_event_release_pmc();
}
+/* Make sure all events can be scheduled into the hardware at
+ * the same time. This is simplified by the fact that we only
+ * need to support 2 simultaneous HW events.
+ */
+static int sparc_check_constraints(unsigned long *events, int n_ev)
+{
+ if (n_ev <= perf_max_events) {
+ u8 msk1, msk2;
+ u16 dummy;
+
+ if (n_ev == 1)
+ return 0;
+ BUG_ON(n_ev != 2);
+ perf_event_decode(events[0], &dummy, &msk1);
+ perf_event_decode(events[1], &dummy, &msk2);
+
+ /* If both events can go on any counter, OK. */
+ if (msk1 == (PIC_UPPER | PIC_LOWER) &&
+ msk2 == (PIC_UPPER | PIC_LOWER))
+ return 0;
+
+ /* If one event is limited to a specific counter,
+ * and the other can go on both, OK.
+ */
+ if ((msk1 == PIC_UPPER || msk1 == PIC_LOWER) &&
+ msk2 == (PIC_UPPER | PIC_LOWER))
+ return 0;
+ if ((msk2 == PIC_UPPER || msk2 == PIC_LOWER) &&
+ msk1 == (PIC_UPPER | PIC_LOWER))
+ return 0;
+
+ /* If the events are fixed to different counters, OK. */
+ if ((msk1 == PIC_UPPER && msk2 == PIC_LOWER) ||
+ (msk1 == PIC_LOWER && msk2 == PIC_UPPER))
+ return 0;
+
+ /* Otherwise, there is a conflict. */
+ }
+
+ return -1;
+}
+
+static int check_excludes(struct perf_event **evts, int n_prev, int n_new)
+{
+ int eu = 0, ek = 0, eh = 0;
+ struct perf_event *event;
+ int i, n, first;
+
+ n = n_prev + n_new;
+ if (n <= 1)
+ return 0;
+
+ first = 1;
+ for (i = 0; i < n; i++) {
+ event = evts[i];
+ if (first) {
+ eu = event->attr.exclude_user;
+ ek = event->attr.exclude_kernel;
+ eh = event->attr.exclude_hv;
+ first = 0;
+ } else if (event->attr.exclude_user != eu ||
+ event->attr.exclude_kernel != ek ||
+ event->attr.exclude_hv != eh) {
+ return -EAGAIN;
+ }
+ }
+
+ return 0;
+}
+
+static int collect_events(struct perf_event *group, int max_count,
+ struct perf_event *evts[], unsigned long *events)
+{
+ struct perf_event *event;
+ int n = 0;
+
+ if (!is_software_event(group)) {
+ if (n >= max_count)
+ return -1;
+ evts[n] = group;
+ events[n++] = group->hw.event_base;
+ }
+ list_for_each_entry(event, &group->sibling_list, group_entry) {
+ if (!is_software_event(event) &&
+ event->state != PERF_EVENT_STATE_OFF) {
+ if (n >= max_count)
+ return -1;
+ evts[n] = event;
+ events[n++] = event->hw.event_base;
+ }
+ }
+ return n;
+}
+
static int __hw_perf_event_init(struct perf_event *event)
{
struct perf_event_attr *attr = &event->attr;
+ struct perf_event *evts[MAX_HWEVENTS];
struct hw_perf_event *hwc = &event->hw;
+ unsigned long events[MAX_HWEVENTS];
const struct perf_event_map *pmap;
u64 enc;
+ int n;
if (atomic_read(&nmi_active) < 0)
return -ENODEV;
- if (attr->type != PERF_TYPE_HARDWARE)
+ if (attr->type == PERF_TYPE_HARDWARE) {
+ if (attr->config >= sparc_pmu->max_events)
+ return -EINVAL;
+ pmap = sparc_pmu->event_map(attr->config);
+ } else if (attr->type == PERF_TYPE_HW_CACHE) {
+ pmap = sparc_map_cache_event(attr->config);
+ if (IS_ERR(pmap))
+ return PTR_ERR(pmap);
+ } else
return -EOPNOTSUPP;
- if (attr->config >= sparc_pmu->max_events)
- return -EINVAL;
-
- perf_event_grab_pmc();
- event->destroy = hw_perf_event_destroy;
-
/* We save the enable bits in the config_base. So to
* turn off sampling just write 'config', and to enable
* things write 'config | config_base'.
@@ -411,15 +877,39 @@ static int __hw_perf_event_init(struct perf_event *event)
if (!attr->exclude_hv)
hwc->config_base |= sparc_pmu->hv_bit;
+ hwc->event_base = perf_event_encode(pmap);
+
+ enc = pmap->encoding;
+
+ n = 0;
+ if (event->group_leader != event) {
+ n = collect_events(event->group_leader,
+ perf_max_events - 1,
+ evts, events);
+ if (n < 0)
+ return -EINVAL;
+ }
+ events[n] = hwc->event_base;
+ evts[n] = event;
+
+ if (check_excludes(evts, n, 1))
+ return -EINVAL;
+
+ if (sparc_check_constraints(events, n + 1))
+ return -EINVAL;
+
+ /* Try to do all error checking before this point, as unwinding
+ * state after grabbing the PMC is difficult.
+ */
+ perf_event_grab_pmc();
+ event->destroy = hw_perf_event_destroy;
+
if (!hwc->sample_period) {
hwc->sample_period = MAX_PERIOD;
hwc->last_period = hwc->sample_period;
atomic64_set(&hwc->period_left, hwc->sample_period);
}
- pmap = sparc_pmu->event_map(attr->config);
-
- enc = pmap->encoding;
if (pmap->pic_mask & PIC_UPPER) {
hwc->idx = PIC_UPPER_INDEX;
enc <<= sparc_pmu->upper_shift;
@@ -472,7 +962,7 @@ void perf_event_print_debug(void)
}
static int __kprobes perf_event_nmi_handler(struct notifier_block *self,
- unsigned long cmd, void *__args)
+ unsigned long cmd, void *__args)
{
struct die_args *args = __args;
struct perf_sample_data data;
@@ -513,7 +1003,7 @@ static int __kprobes perf_event_nmi_handler(struct notifier_block *self,
continue;
if (perf_event_overflow(event, 1, &data, regs))
- sparc_pmu_disable_event(hwc, idx);
+ sparc_pmu_disable_event(cpuc, hwc, idx);
}
return NOTIFY_STOP;
@@ -525,8 +1015,15 @@ static __read_mostly struct notifier_block perf_event_nmi_notifier = {
static bool __init supported_pmu(void)
{
- if (!strcmp(sparc_pmu_type, "ultra3i")) {
- sparc_pmu = &ultra3i_pmu;
+ if (!strcmp(sparc_pmu_type, "ultra3") ||
+ !strcmp(sparc_pmu_type, "ultra3+") ||
+ !strcmp(sparc_pmu_type, "ultra3i") ||
+ !strcmp(sparc_pmu_type, "ultra4+")) {
+ sparc_pmu = &ultra3_pmu;
+ return true;
+ }
+ if (!strcmp(sparc_pmu_type, "niagara")) {
+ sparc_pmu = &niagara1_pmu;
return true;
}
if (!strcmp(sparc_pmu_type, "niagara2")) {
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/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index a70a5e1904d9..1886d37d411b 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -265,7 +265,7 @@ static void flush_dcache(unsigned long pfn)
struct page *page;
page = pfn_to_page(pfn);
- if (page && page_mapping(page)) {
+ if (page) {
unsigned long pg_flags;
pg_flags = page->flags;
diff --git a/arch/sparc/oprofile/init.c b/arch/sparc/oprofile/init.c
index f97cb8b6ee5f..f9024bccff16 100644
--- a/arch/sparc/oprofile/init.c
+++ b/arch/sparc/oprofile/init.c
@@ -11,6 +11,7 @@
#include <linux/oprofile.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/param.h> /* for HZ */
#ifdef CONFIG_SPARC64
#include <linux/notifier.h>
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/drivers/line.c b/arch/um/drivers/line.c
index 14a102e877d6..cf8a97f34518 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -5,6 +5,7 @@
#include "linux/irqreturn.h"
#include "linux/kd.h"
+#include "linux/sched.h"
#include "chan_kern.h"
#include "irq_kern.h"
#include "irq_user.h"
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
index 19930081d3d8..4ebc8a34738f 100644
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -7,6 +7,7 @@
#include "linux/interrupt.h"
#include "linux/list.h"
#include "linux/mutex.h"
+#include "linux/workqueue.h"
#include "asm/atomic.h"
#include "init.h"
#include "irq_kern.h"
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/um/kernel/irq.c b/arch/um/kernel/irq.c
index 454cdb43e351..039270b9b73b 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -10,6 +10,7 @@
#include "linux/interrupt.h"
#include "linux/kernel_stat.h"
#include "linux/module.h"
+#include "linux/sched.h"
#include "linux/seq_file.h"
#include "as-layout.h"
#include "kern_util.h"
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 8da93745c087..07e01149e3bf 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -86,10 +86,6 @@ config STACKTRACE_SUPPORT
config HAVE_LATENCYTOP_SUPPORT
def_bool y
-config FAST_CMPXCHG_LOCAL
- bool
- default y
-
config MMU
def_bool y
@@ -495,7 +491,7 @@ if PARAVIRT_GUEST
source "arch/x86/xen/Kconfig"
config VMI
- bool "VMI Guest support"
+ bool "VMI Guest support (DEPRECATED)"
select PARAVIRT
depends on X86_32
---help---
@@ -504,6 +500,15 @@ config VMI
at the moment), by linking the kernel to a GPL-ed ROM module
provided by the hypervisor.
+ As of September 2009, VMware has started a phased retirement
+ of this feature from VMware's products. Please see
+ feature-removal-schedule.txt for details. If you are
+ planning to enable this option, please note that you cannot
+ live migrate a VMI enabled VM to a future VMware product,
+ which doesn't support VMI. So if you expect your kernel to
+ seamlessly migrate to newer VMware products, keep this
+ disabled.
+
config KVM_CLOCK
bool "KVM paravirtualized clock"
select PARAVIRT
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index 527519b8a9f9..f2824fb8c79c 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -400,7 +400,7 @@ config X86_TSC
config X86_CMPXCHG64
def_bool y
- depends on X86_PAE || X86_64
+ depends on X86_PAE || X86_64 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MATOM
# this should be set for all -march=.. options where the compiler
# generates cmov.
@@ -412,6 +412,7 @@ config X86_MINIMUM_CPU_FAMILY
int
default "64" if X86_64
default "6" if X86_32 && X86_P6_NOP
+ default "5" if X86_32 && X86_CMPXCHG64
default "4" if X86_32 && (X86_XADD || X86_CMPXCHG || X86_BSWAP || X86_WP_WORKS_OK)
default "3"
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/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/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
index 74619c4f9fda..07c842659090 100644
--- a/arch/x86/ia32/ia32entry.S
+++ b/arch/x86/ia32/ia32entry.S
@@ -21,8 +21,8 @@
#define __AUDIT_ARCH_LE 0x40000000
#ifndef CONFIG_AUDITSYSCALL
-#define sysexit_audit int_ret_from_sys_call
-#define sysretl_audit int_ret_from_sys_call
+#define sysexit_audit ia32_ret_from_sys_call
+#define sysretl_audit ia32_ret_from_sys_call
#endif
#define IA32_NR_syscalls ((ia32_syscall_end - ia32_sys_call_table)/8)
@@ -39,12 +39,12 @@
.endm
/* clobbers %eax */
- .macro CLEAR_RREGS _r9=rax
+ .macro CLEAR_RREGS offset=0, _r9=rax
xorl %eax,%eax
- movq %rax,R11(%rsp)
- movq %rax,R10(%rsp)
- movq %\_r9,R9(%rsp)
- movq %rax,R8(%rsp)
+ movq %rax,\offset+R11(%rsp)
+ movq %rax,\offset+R10(%rsp)
+ movq %\_r9,\offset+R9(%rsp)
+ movq %rax,\offset+R8(%rsp)
.endm
/*
@@ -172,6 +172,10 @@ sysexit_from_sys_call:
movl RIP-R11(%rsp),%edx /* User %eip */
CFI_REGISTER rip,rdx
RESTORE_ARGS 1,24,1,1,1,1
+ xorq %r8,%r8
+ xorq %r9,%r9
+ xorq %r10,%r10
+ xorq %r11,%r11
popfq
CFI_ADJUST_CFA_OFFSET -8
/*CFI_RESTORE rflags*/
@@ -202,7 +206,7 @@ sysexit_from_sys_call:
.macro auditsys_exit exit,ebpsave=RBP
testl $(_TIF_ALLWORK_MASK & ~_TIF_SYSCALL_AUDIT),TI_flags(%r10)
- jnz int_ret_from_sys_call
+ jnz ia32_ret_from_sys_call
TRACE_IRQS_ON
sti
movl %eax,%esi /* second arg, syscall return value */
@@ -218,8 +222,9 @@ sysexit_from_sys_call:
cli
TRACE_IRQS_OFF
testl %edi,TI_flags(%r10)
- jnz int_with_check
- jmp \exit
+ jz \exit
+ CLEAR_RREGS -ARGOFFSET
+ jmp int_with_check
.endm
sysenter_auditsys:
@@ -329,6 +334,9 @@ sysretl_from_sys_call:
CFI_REGISTER rip,rcx
movl EFLAGS-ARGOFFSET(%rsp),%r11d
/*CFI_REGISTER rflags,r11*/
+ xorq %r10,%r10
+ xorq %r9,%r9
+ xorq %r8,%r8
TRACE_IRQS_ON
movl RSP-ARGOFFSET(%rsp),%esp
CFI_RESTORE rsp
@@ -353,7 +361,7 @@ cstar_tracesys:
#endif
xchgl %r9d,%ebp
SAVE_REST
- CLEAR_RREGS r9
+ CLEAR_RREGS 0, r9
movq $-ENOSYS,RAX(%rsp) /* ptrace can change this for a bad syscall */
movq %rsp,%rdi /* &pt_regs -> arg1 */
call syscall_trace_enter
@@ -425,6 +433,8 @@ ia32_do_call:
call *ia32_sys_call_table(,%rax,8) # xxx: rip relative
ia32_sysret:
movq %rax,RAX-ARGOFFSET(%rsp)
+ia32_ret_from_sys_call:
+ CLEAR_RREGS -ARGOFFSET
jmp int_ret_from_sys_call
ia32_tracesys:
@@ -442,8 +452,8 @@ END(ia32_syscall)
ia32_badsys:
movq $0,ORIG_RAX-ARGOFFSET(%rsp)
- movq $-ENOSYS,RAX-ARGOFFSET(%rsp)
- jmp int_ret_from_sys_call
+ movq $-ENOSYS,%rax
+ jmp ia32_sysret
quiet_ni_syscall:
movq $-ENOSYS,%rax
@@ -832,4 +842,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/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/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 3be000435fad..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,
@@ -796,6 +797,7 @@ asmlinkage void kvm_handle_fault_on_reboot(void);
#define KVM_ARCH_WANT_MMU_NOTIFIER
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
int kvm_age_hva(struct kvm *kvm, unsigned long hva);
+void kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte);
int cpuid_maxphyaddr(struct kvm_vcpu *vcpu);
int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);
int kvm_arch_interrupt_allowed(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index b608a64c5814..f1363b72364f 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -133,6 +133,8 @@ static inline void winchip_mcheck_init(struct cpuinfo_x86 *c) {}
static inline void enable_p5_mce(void) {}
#endif
+extern void (*x86_mce_decode_callback)(struct mce *m);
+
void mce_setup(struct mce *m);
void mce_log(struct mce *m);
DECLARE_PER_CPU(struct sys_device, mce_dev);
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 8aebcc41041d..efb38994859c 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -840,42 +840,22 @@ static __always_inline void __raw_spin_unlock(struct raw_spinlock *lock)
static inline unsigned long __raw_local_save_flags(void)
{
- unsigned long f;
-
- asm volatile(paravirt_alt(PARAVIRT_CALL)
- : "=a"(f)
- : paravirt_type(pv_irq_ops.save_fl),
- paravirt_clobber(CLBR_EAX)
- : "memory", "cc");
- return f;
+ return PVOP_CALLEE0(unsigned long, pv_irq_ops.save_fl);
}
static inline void raw_local_irq_restore(unsigned long f)
{
- asm volatile(paravirt_alt(PARAVIRT_CALL)
- : "=a"(f)
- : PV_FLAGS_ARG(f),
- paravirt_type(pv_irq_ops.restore_fl),
- paravirt_clobber(CLBR_EAX)
- : "memory", "cc");
+ PVOP_VCALLEE1(pv_irq_ops.restore_fl, f);
}
static inline void raw_local_irq_disable(void)
{
- asm volatile(paravirt_alt(PARAVIRT_CALL)
- :
- : paravirt_type(pv_irq_ops.irq_disable),
- paravirt_clobber(CLBR_EAX)
- : "memory", "eax", "cc");
+ PVOP_VCALLEE0(pv_irq_ops.irq_disable);
}
static inline void raw_local_irq_enable(void)
{
- asm volatile(paravirt_alt(PARAVIRT_CALL)
- :
- : paravirt_type(pv_irq_ops.irq_enable),
- paravirt_clobber(CLBR_EAX)
- : "memory", "eax", "cc");
+ PVOP_VCALLEE0(pv_irq_ops.irq_enable);
}
static inline unsigned long __raw_local_irq_save(void)
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index dd0f5b32489d..9357473c8da0 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -494,10 +494,11 @@ int paravirt_disable_iospace(void);
#define EXTRA_CLOBBERS
#define VEXTRA_CLOBBERS
#else /* CONFIG_X86_64 */
+/* [re]ax isn't an arg, but the return val */
#define PVOP_VCALL_ARGS \
unsigned long __edi = __edi, __esi = __esi, \
- __edx = __edx, __ecx = __ecx
-#define PVOP_CALL_ARGS PVOP_VCALL_ARGS, __eax
+ __edx = __edx, __ecx = __ecx, __eax = __eax
+#define PVOP_CALL_ARGS PVOP_VCALL_ARGS
#define PVOP_CALL_ARG1(x) "D" ((unsigned long)(x))
#define PVOP_CALL_ARG2(x) "S" ((unsigned long)(x))
@@ -509,6 +510,7 @@ int paravirt_disable_iospace(void);
"=c" (__ecx)
#define PVOP_CALL_CLOBBERS PVOP_VCALL_CLOBBERS, "=a" (__eax)
+/* void functions are still allowed [re]ax for scratch */
#define PVOP_VCALLEE_CLOBBERS "=a" (__eax)
#define PVOP_CALLEE_CLOBBERS PVOP_VCALLEE_CLOBBERS
@@ -583,8 +585,8 @@ int paravirt_disable_iospace(void);
VEXTRA_CLOBBERS, \
pre, post, ##__VA_ARGS__)
-#define __PVOP_VCALLEESAVE(rettype, op, pre, post, ...) \
- ____PVOP_CALL(rettype, op.func, CLBR_RET_REG, \
+#define __PVOP_VCALLEESAVE(op, pre, post, ...) \
+ ____PVOP_VCALL(op.func, CLBR_RET_REG, \
PVOP_VCALLEE_CLOBBERS, , \
pre, post, ##__VA_ARGS__)
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/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 183c3457d2f4..b1598a9436d0 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -85,6 +85,18 @@ 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)
+{
+ pr_emerg("No human readable MCE decoding support on this CPU type.\n");
+ pr_emerg("Run the message through 'mcelog --ascii' to decode.\n");
+}
+
+/*
+ * 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);
/* MCA banks polled by the period polling timer for corrected events */
DEFINE_PER_CPU(mce_banks_t, mce_poll_banks) = {
@@ -165,46 +177,46 @@ void mce_log(struct mce *mce)
set_bit(0, &mce_need_notify);
}
-void __weak decode_mce(struct mce *m)
-{
- return;
-}
-
static void print_mce(struct mce *m)
{
- printk(KERN_EMERG
- "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
+ pr_emerg("CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
m->extcpu, m->mcgstatus, m->bank, m->status);
+
if (m->ip) {
- printk(KERN_EMERG "RIP%s %02x:<%016Lx> ",
- !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
- m->cs, m->ip);
+ pr_emerg("RIP%s %02x:<%016Lx> ",
+ !(m->mcgstatus & MCG_STATUS_EIPV) ? " !INEXACT!" : "",
+ m->cs, m->ip);
+
if (m->cs == __KERNEL_CS)
print_symbol("{%s}", m->ip);
- printk(KERN_CONT "\n");
+ pr_cont("\n");
}
- printk(KERN_EMERG "TSC %llx ", m->tsc);
+
+ pr_emerg("TSC %llx ", m->tsc);
if (m->addr)
- printk(KERN_CONT "ADDR %llx ", m->addr);
+ pr_cont("ADDR %llx ", m->addr);
if (m->misc)
- printk(KERN_CONT "MISC %llx ", m->misc);
- printk(KERN_CONT "\n");
- printk(KERN_EMERG "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
- m->cpuvendor, m->cpuid, m->time, m->socketid,
- m->apicid);
+ pr_cont("MISC %llx ", m->misc);
+
+ pr_cont("\n");
+ pr_emerg("PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
+ m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid);
- decode_mce(m);
+ /*
+ * Print out human-readable details about the MCE error,
+ * (if the CPU has an implementation for that):
+ */
+ x86_mce_decode_callback(m);
}
static void print_mce_head(void)
{
- printk(KERN_EMERG "\nHARDWARE ERROR\n");
+ pr_emerg("\nHARDWARE ERROR\n");
}
static void print_mce_tail(void)
{
- printk(KERN_EMERG "This is not a software problem!\n"
- "Run through mcelog --ascii to decode and contact your hardware vendor\n");
+ pr_emerg("This is not a software problem!\n");
}
#define PANIC_TIMEOUT 5 /* 5 seconds */
@@ -218,6 +230,7 @@ static atomic_t mce_fake_paniced;
static void wait_for_panic(void)
{
long timeout = PANIC_TIMEOUT*USEC_PER_SEC;
+
preempt_disable();
local_irq_enable();
while (timeout-- > 0)
@@ -285,6 +298,7 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
static int msr_to_offset(u32 msr)
{
unsigned bank = __get_cpu_var(injectm.bank);
+
if (msr == rip_msr)
return offsetof(struct mce, ip);
if (msr == MSR_IA32_MCx_STATUS(bank))
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel.c b/arch/x86/kernel/cpu/mcheck/mce_intel.c
index 889f665fe93d..7c785634af2b 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_intel.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_intel.c
@@ -8,6 +8,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
+#include <linux/sched.h>
#include <asm/apic.h>
#include <asm/processor.h>
#include <asm/msr.h>
diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c
index f04e72527604..3c1b12d461d1 100644
--- a/arch/x86/kernel/cpu/mtrr/if.c
+++ b/arch/x86/kernel/cpu/mtrr/if.c
@@ -96,17 +96,24 @@ mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos)
unsigned long long base, size;
char *ptr;
char line[LINE_SIZE];
+ int length;
size_t linelen;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- if (!len)
- return -EINVAL;
memset(line, 0, LINE_SIZE);
- if (len > LINE_SIZE)
- len = LINE_SIZE;
- if (copy_from_user(line, buf, len - 1))
+
+ length = len;
+ length--;
+
+ if (length > LINE_SIZE - 1)
+ length = LINE_SIZE - 1;
+
+ if (length < 0)
+ return -EINVAL;
+
+ if (copy_from_user(line, buf, length))
return -EFAULT;
linelen = strlen(line);
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c
index 85419bb7d4ab..d17d482a04f4 100644
--- a/arch/x86/kernel/e820.c
+++ b/arch/x86/kernel/e820.c
@@ -1378,8 +1378,8 @@ static unsigned long ram_alignment(resource_size_t pos)
if (mb < 16)
return 1024*1024;
- /* To 32MB for anything above that */
- return 32*1024*1024;
+ /* To 64MB for anything above that */
+ return 64*1024*1024;
}
#define MAX_RESOURCE_SIZE ((resource_size_t)-1)
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c
index 41fd965c80c6..b9c830c12b4a 100644
--- a/arch/x86/kernel/early_printk.c
+++ b/arch/x86/kernel/early_printk.c
@@ -206,8 +206,11 @@ static int __init setup_early_printk(char *buf)
while (*buf != '\0') {
if (!strncmp(buf, "serial", 6)) {
- early_serial_init(buf + 6);
+ buf += 6;
+ early_serial_init(buf);
early_console_register(&early_serial_console, keep);
+ if (!strncmp(buf, ",ttyS", 5))
+ buf += 5;
}
if (!strncmp(buf, "ttyS", 4)) {
early_serial_init(buf + 4);
diff --git a/arch/x86/kernel/i386_ksyms_32.c b/arch/x86/kernel/i386_ksyms_32.c
index 1736c5a725aa..9c3bd4a2050e 100644
--- a/arch/x86/kernel/i386_ksyms_32.c
+++ b/arch/x86/kernel/i386_ksyms_32.c
@@ -15,8 +15,10 @@ EXPORT_SYMBOL(mcount);
* the export, but dont use it from C code, it is used
* by assembly code and is not using C calling convention!
*/
+#ifndef CONFIG_X86_CMPXCHG64
extern void cmpxchg8b_emu(void);
EXPORT_SYMBOL(cmpxchg8b_emu);
+#endif
/* Networking helper routines. */
EXPORT_SYMBOL(csum_partial_copy_generic);
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 74656d1d4e30..04bbd5278568 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -63,10 +63,10 @@ static int show_other_interrupts(struct seq_file *p, int prec)
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->irq_spurious_count);
seq_printf(p, " Spurious interrupts\n");
- seq_printf(p, "%*s: ", prec, "CNT");
+ seq_printf(p, "%*s: ", prec, "PMI");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs);
- seq_printf(p, " Performance counter interrupts\n");
+ seq_printf(p, " Performance monitoring interrupts\n");
seq_printf(p, "%*s: ", prec, "PND");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->apic_pending_irqs);
diff --git a/arch/x86/kernel/kgdb.c b/arch/x86/kernel/kgdb.c
index 8d82a77a3f3b..e9afae9f799b 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] = (unsigned long)&regs->sp;
+ }
#else
gdb_regs[GDB_R8] = regs->r8;
gdb_regs[GDB_R9] = regs->r9;
@@ -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/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 64b838eac18c..b2a71dca5642 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -35,7 +35,7 @@ int iommu_detected __read_mostly = 0;
/*
* This variable becomes 1 if iommu=pt is passed on the kernel command line.
- * If this variable is 1, IOMMU implementations do no DMA ranslation for
+ * If this variable is 1, IOMMU implementations do no DMA translation for
* devices and allow every device to access to whole physical memory. This is
* useful if a user want to use an IOMMU only for KVM device assignment to
* guests and not for driver dma translation.
@@ -311,7 +311,7 @@ void pci_iommu_shutdown(void)
amd_iommu_shutdown();
}
/* Must execute after PCI subsystem */
-fs_initcall(pci_iommu_init);
+rootfs_initcall(pci_iommu_init);
#ifdef CONFIG_PCI
/* Many VIA bridges seem to corrupt data for DAC. Disable it here */
diff --git a/arch/x86/kernel/pci-gart_64.c b/arch/x86/kernel/pci-gart_64.c
index 98a827ee9ed7..a7f1b64f86e0 100644
--- a/arch/x86/kernel/pci-gart_64.c
+++ b/arch/x86/kernel/pci-gart_64.c
@@ -16,6 +16,7 @@
#include <linux/agp_backend.h>
#include <linux/init.h>
#include <linux/mm.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 27349f92a6d7..d9d8d91741a1 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -4,6 +4,7 @@
#include <linux/pm.h>
#include <linux/efi.h>
#include <linux/dmi.h>
+#include <linux/sched.h>
#include <linux/tboot.h>
#include <acpi/reboot.h>
#include <asm/io.h>
@@ -33,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/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/time.c b/arch/x86/kernel/time.c
index dcb00d278512..be2573448ed9 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -38,7 +38,8 @@ unsigned long profile_pc(struct pt_regs *regs)
#ifdef CONFIG_FRAME_POINTER
return *(unsigned long *)(regs->bp + sizeof(long));
#else
- unsigned long *sp = (unsigned long *)regs->sp;
+ unsigned long *sp =
+ (unsigned long *)kernel_stack_pointer(regs);
/*
* Return address is either directly at stack pointer
* or above a saved flags. Eflags has bits 22-31 zero,
diff --git a/arch/x86/kernel/trampoline.c b/arch/x86/kernel/trampoline.c
index 699f7eeb896a..cd022121cab6 100644
--- a/arch/x86/kernel/trampoline.c
+++ b/arch/x86/kernel/trampoline.c
@@ -3,8 +3,16 @@
#include <asm/trampoline.h>
#include <asm/e820.h>
+#if defined(CONFIG_X86_64) && defined(CONFIG_ACPI_SLEEP)
+#define __trampinit
+#define __trampinitdata
+#else
+#define __trampinit __cpuinit
+#define __trampinitdata __cpuinitdata
+#endif
+
/* ready for x86_64 and x86 */
-unsigned char *__cpuinitdata trampoline_base = __va(TRAMPOLINE_BASE);
+unsigned char *__trampinitdata trampoline_base = __va(TRAMPOLINE_BASE);
void __init reserve_trampoline_memory(void)
{
@@ -26,7 +34,7 @@ void __init reserve_trampoline_memory(void)
* bootstrap into the page concerned. The caller
* has made sure it's suitably aligned.
*/
-unsigned long __cpuinit setup_trampoline(void)
+unsigned long __trampinit setup_trampoline(void)
{
memcpy(trampoline_base, trampoline_data, TRAMPOLINE_SIZE);
return virt_to_phys(trampoline_base);
diff --git a/arch/x86/kernel/trampoline_64.S b/arch/x86/kernel/trampoline_64.S
index 596d54c660a5..3af2dff58b21 100644
--- a/arch/x86/kernel/trampoline_64.S
+++ b/arch/x86/kernel/trampoline_64.S
@@ -32,8 +32,12 @@
#include <asm/segment.h>
#include <asm/processor-flags.h>
+#ifdef CONFIG_ACPI_SLEEP
+.section .rodata, "a", @progbits
+#else
/* We can free up the trampoline after bootup if cpu hotplug is not supported. */
__CPUINITRODATA
+#endif
.code16
ENTRY(trampoline_data)
diff --git a/arch/x86/kernel/vmi_32.c b/arch/x86/kernel/vmi_32.c
index 31e6f6cfe53e..d430e4c30193 100644
--- a/arch/x86/kernel/vmi_32.c
+++ b/arch/x86/kernel/vmi_32.c
@@ -648,7 +648,7 @@ static inline int __init activate_vmi(void)
pv_info.paravirt_enabled = 1;
pv_info.kernel_rpl = kernel_cs & SEGMENT_RPL_MASK;
- pv_info.name = "vmi";
+ pv_info.name = "vmi [deprecated]";
pv_init_ops.patch = vmi_patch;
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..b857ca385919 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -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 1ae5ceba7eb2..3ca776755ae6 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)
@@ -664,7 +658,7 @@ static void start_apic_timer(struct kvm_lapic *apic)
{
ktime_t now = apic->lapic_timer.timer.base->get_time();
- apic->lapic_timer.period = apic_get_reg(apic, APIC_TMICT) *
+ apic->lapic_timer.period = (u64)apic_get_reg(apic, APIC_TMICT) *
APIC_BUS_CYCLE_NS * apic->divide_count;
atomic_set(&apic->lapic_timer.pending, 0);
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index eca41ae9f453..20a2cd168fb9 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -156,6 +156,8 @@ module_param(oos_shadow, bool, 0644);
#define CREATE_TRACE_POINTS
#include "mmutrace.h"
+#define SPTE_HOST_WRITEABLE (1ULL << PT_FIRST_AVAIL_BITS_SHIFT)
+
#define SHADOW_PT_INDEX(addr, level) PT64_INDEX(addr, level)
struct kvm_rmap_desc {
@@ -634,9 +636,7 @@ static void rmap_remove(struct kvm *kvm, u64 *spte)
if (*spte & shadow_accessed_mask)
kvm_set_pfn_accessed(pfn);
if (is_writeble_pte(*spte))
- kvm_release_pfn_dirty(pfn);
- else
- kvm_release_pfn_clean(pfn);
+ kvm_set_pfn_dirty(pfn);
rmapp = gfn_to_rmap(kvm, sp->gfns[spte - sp->spt], sp->role.level);
if (!*rmapp) {
printk(KERN_ERR "rmap_remove: %p %llx 0->BUG\n", spte, *spte);
@@ -748,7 +748,7 @@ static int rmap_write_protect(struct kvm *kvm, u64 gfn)
return write_protected;
}
-static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp)
+static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data)
{
u64 *spte;
int need_tlb_flush = 0;
@@ -763,8 +763,45 @@ static int kvm_unmap_rmapp(struct kvm *kvm, unsigned long *rmapp)
return need_tlb_flush;
}
-static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
- int (*handler)(struct kvm *kvm, unsigned long *rmapp))
+static int kvm_set_pte_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data)
+{
+ int need_flush = 0;
+ u64 *spte, new_spte;
+ pte_t *ptep = (pte_t *)data;
+ pfn_t new_pfn;
+
+ WARN_ON(pte_huge(*ptep));
+ new_pfn = pte_pfn(*ptep);
+ spte = rmap_next(kvm, rmapp, NULL);
+ while (spte) {
+ BUG_ON(!is_shadow_present_pte(*spte));
+ rmap_printk("kvm_set_pte_rmapp: spte %p %llx\n", spte, *spte);
+ need_flush = 1;
+ if (pte_write(*ptep)) {
+ rmap_remove(kvm, spte);
+ __set_spte(spte, shadow_trap_nonpresent_pte);
+ spte = rmap_next(kvm, rmapp, NULL);
+ } else {
+ new_spte = *spte &~ (PT64_BASE_ADDR_MASK);
+ new_spte |= (u64)new_pfn << PAGE_SHIFT;
+
+ new_spte &= ~PT_WRITABLE_MASK;
+ new_spte &= ~SPTE_HOST_WRITEABLE;
+ if (is_writeble_pte(*spte))
+ kvm_set_pfn_dirty(spte_to_pfn(*spte));
+ __set_spte(spte, new_spte);
+ spte = rmap_next(kvm, rmapp, spte);
+ }
+ }
+ if (need_flush)
+ kvm_flush_remote_tlbs(kvm);
+
+ return 0;
+}
+
+static int kvm_handle_hva(struct kvm *kvm, unsigned long hva, u64 data,
+ int (*handler)(struct kvm *kvm, unsigned long *rmapp,
+ u64 data))
{
int i, j;
int retval = 0;
@@ -786,13 +823,15 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
if (hva >= start && hva < end) {
gfn_t gfn_offset = (hva - start) >> PAGE_SHIFT;
- retval |= handler(kvm, &memslot->rmap[gfn_offset]);
+ retval |= handler(kvm, &memslot->rmap[gfn_offset],
+ data);
for (j = 0; j < KVM_NR_PAGE_SIZES - 1; ++j) {
int idx = gfn_offset;
idx /= KVM_PAGES_PER_HPAGE(PT_DIRECTORY_LEVEL + j);
retval |= handler(kvm,
- &memslot->lpage_info[j][idx].rmap_pde);
+ &memslot->lpage_info[j][idx].rmap_pde,
+ data);
}
}
}
@@ -802,10 +841,15 @@ static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
int kvm_unmap_hva(struct kvm *kvm, unsigned long hva)
{
- return kvm_handle_hva(kvm, hva, kvm_unmap_rmapp);
+ return kvm_handle_hva(kvm, hva, 0, kvm_unmap_rmapp);
}
-static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp)
+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);
+}
+
+static int kvm_age_rmapp(struct kvm *kvm, unsigned long *rmapp, u64 data)
{
u64 *spte;
int young = 0;
@@ -841,13 +885,13 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
gfn = unalias_gfn(vcpu->kvm, gfn);
rmapp = gfn_to_rmap(vcpu->kvm, gfn, sp->role.level);
- kvm_unmap_rmapp(vcpu->kvm, rmapp);
+ kvm_unmap_rmapp(vcpu->kvm, rmapp, 0);
kvm_flush_remote_tlbs(vcpu->kvm);
}
int kvm_age_hva(struct kvm *kvm, unsigned long hva)
{
- return kvm_handle_hva(kvm, hva, kvm_age_rmapp);
+ return kvm_handle_hva(kvm, hva, 0, kvm_age_rmapp);
}
#ifdef MMU_DEBUG
@@ -1756,7 +1800,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
unsigned pte_access, int user_fault,
int write_fault, int dirty, int level,
gfn_t gfn, pfn_t pfn, bool speculative,
- bool can_unsync)
+ bool can_unsync, bool reset_host_protection)
{
u64 spte;
int ret = 0;
@@ -1783,6 +1827,9 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn,
kvm_is_mmio_pfn(pfn));
+ if (reset_host_protection)
+ spte |= SPTE_HOST_WRITEABLE;
+
spte |= (u64)pfn << PAGE_SHIFT;
if ((pte_access & ACC_WRITE_MASK)
@@ -1828,7 +1875,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
unsigned pt_access, unsigned pte_access,
int user_fault, int write_fault, int dirty,
int *ptwrite, int level, gfn_t gfn,
- pfn_t pfn, bool speculative)
+ pfn_t pfn, bool speculative,
+ bool reset_host_protection)
{
int was_rmapped = 0;
int was_writeble = is_writeble_pte(*sptep);
@@ -1860,7 +1908,8 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
}
if (set_spte(vcpu, sptep, pte_access, user_fault, write_fault,
- dirty, level, gfn, pfn, speculative, true)) {
+ dirty, level, gfn, pfn, speculative, true,
+ reset_host_protection)) {
if (write_fault)
*ptwrite = 1;
kvm_x86_ops->tlb_flush(vcpu);
@@ -1877,8 +1926,7 @@ static void mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
page_header_update_slot(vcpu->kvm, sptep, gfn);
if (!was_rmapped) {
rmap_count = rmap_add(vcpu, sptep, gfn);
- if (!is_rmap_spte(*sptep))
- kvm_release_pfn_clean(pfn);
+ kvm_release_pfn_clean(pfn);
if (rmap_count > RMAP_RECYCLE_THRESHOLD)
rmap_recycle(vcpu, sptep, gfn);
} else {
@@ -1909,7 +1957,7 @@ static int __direct_map(struct kvm_vcpu *vcpu, gpa_t v, int write,
if (iterator.level == level) {
mmu_set_spte(vcpu, iterator.sptep, ACC_ALL, ACC_ALL,
0, write, 1, &pt_write,
- level, gfn, pfn, false);
+ level, gfn, pfn, false, true);
++vcpu->stat.pf_fixed;
break;
}
@@ -2737,7 +2785,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/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h
index d2fec9c12d22..72558f8ff3f5 100644
--- a/arch/x86/kvm/paging_tmpl.h
+++ b/arch/x86/kvm/paging_tmpl.h
@@ -273,9 +273,13 @@ static void FNAME(update_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *page,
if (mmu_notifier_retry(vcpu, vcpu->arch.update_pte.mmu_seq))
return;
kvm_get_pfn(pfn);
+ /*
+ * we call mmu_set_spte() with reset_host_protection = true beacuse that
+ * vcpu->arch.update_pte.pfn was fetched from get_user_pages(write = 1).
+ */
mmu_set_spte(vcpu, spte, page->role.access, pte_access, 0, 0,
gpte & PT_DIRTY_MASK, NULL, PT_PAGE_TABLE_LEVEL,
- gpte_to_gfn(gpte), pfn, true);
+ gpte_to_gfn(gpte), pfn, true, true);
}
/*
@@ -308,7 +312,7 @@ static u64 *FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
user_fault, write_fault,
gw->ptes[gw->level-1] & PT_DIRTY_MASK,
ptwrite, level,
- gw->gfn, pfn, false);
+ gw->gfn, pfn, false, true);
break;
}
@@ -558,6 +562,7 @@ static void FNAME(prefetch_page)(struct kvm_vcpu *vcpu,
static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
{
int i, offset, nr_present;
+ bool reset_host_protection;
offset = nr_present = 0;
@@ -595,9 +600,16 @@ static int FNAME(sync_page)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp)
nr_present++;
pte_access = sp->role.access & FNAME(gpte_access)(vcpu, gpte);
+ if (!(sp->spt[i] & SPTE_HOST_WRITEABLE)) {
+ pte_access &= ~ACC_WRITE_MASK;
+ reset_host_protection = 0;
+ } else {
+ reset_host_protection = 1;
+ }
set_spte(vcpu, &sp->spt[i], pte_access, 0, 0,
is_dirty_gpte(gpte), PT_PAGE_TABLE_LEVEL, gfn,
- spte_to_pfn(sp->spt[i]), true, false);
+ spte_to_pfn(sp->spt[i]), true, false,
+ reset_host_protection);
}
return !nr_present;
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 944cc9c04b3c..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,15 +764,16 @@ 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;
vcpu->cpu = cpu;
kvm_migrate_timers(vcpu);
svm->asid_generation = 0;
@@ -785,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)
@@ -1058,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)
@@ -1178,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;
@@ -1192,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) {
@@ -1221,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))
@@ -1249,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
@@ -1262,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.
@@ -1275,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;
@@ -1289,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;
}
@@ -1299,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);
@@ -1388,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;
@@ -1787,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",
@@ -1835,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;
@@ -1855,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;
@@ -1875,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");
@@ -1905,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;
@@ -1918,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;
@@ -1935,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");
@@ -1948,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;
@@ -2006,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);
@@ -2021,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;
@@ -2057,10 +2054,14 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 *data)
switch (ecx) {
case MSR_IA32_TSC: {
- u64 tsc;
+ u64 tsc_offset;
+
+ if (is_nested(svm))
+ tsc_offset = svm->nested.hsave->control.tsc_offset;
+ else
+ tsc_offset = svm->vmcb->control.tsc_offset;
- rdtscll(tsc);
- *data = svm->vmcb->control.tsc_offset + tsc;
+ *data = tsc_offset + native_read_tsc();
break;
}
case MSR_K6_STAR:
@@ -2122,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;
@@ -2146,10 +2147,17 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, unsigned ecx, u64 data)
switch (ecx) {
case MSR_IA32_TSC: {
- u64 tsc;
+ u64 tsc_offset = data - native_read_tsc();
+ u64 g_tsc_offset = 0;
+
+ if (is_nested(svm)) {
+ g_tsc_offset = svm->vmcb->control.tsc_offset -
+ svm->nested.hsave->control.tsc_offset;
+ svm->nested.hsave->control.tsc_offset = tsc_offset;
+ }
+
+ svm->vmcb->control.tsc_offset = tsc_offset + g_tsc_offset;
- rdtscll(tsc);
- svm->vmcb->control.tsc_offset = data - tsc;
break;
}
case MSR_K6_STAR:
@@ -2208,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)
@@ -2224,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;
/*
@@ -2252,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,
@@ -2308,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);
@@ -2370,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)
@@ -2451,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)
@@ -2575,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 f3812014bd0b..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;
@@ -709,7 +708,7 @@ static void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
if (vcpu->cpu != cpu) {
vcpu_clear(vmx);
kvm_migrate_timers(vcpu);
- vpid_sync_vcpu_all(vmx);
+ set_bit(KVM_REQ_TLB_FLUSH, &vcpu->requests);
local_irq_disable();
list_add(&vmx->local_vcpus_link,
&per_cpu(vcpus_on_cpu, cpu));
@@ -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 be451ee44249..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);
}
@@ -1591,6 +1612,8 @@ static int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid,
if (cpuid->nent < 1)
goto out;
+ if (cpuid->nent > KVM_MAX_CPUID_ENTRIES)
+ cpuid->nent = KVM_MAX_CPUID_ENTRIES;
r = -ENOMEM;
cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry2) * cpuid->nent);
if (!cpuid_entries)
@@ -2036,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;
@@ -2068,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;
@@ -2180,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
@@ -2290,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,
@@ -2755,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;
@@ -2781,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
@@ -2859,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;
@@ -2967,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;
@@ -2997,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)
{
@@ -3070,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)
{
@@ -3081,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) {
@@ -3125,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) {
@@ -3159,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;
@@ -3293,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)
@@ -3331,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;
@@ -3451,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))
@@ -3523,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) {
@@ -3559,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))
@@ -3584,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;
}
@@ -3613,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)
@@ -3639,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);
@@ -3680,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;
@@ -3706,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);
@@ -3734,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()) {
@@ -3752,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);
@@ -3792,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) {
@@ -3809,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)
@@ -3843,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);
@@ -3877,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;
@@ -4101,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,
@@ -4129,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);
@@ -4153,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);
@@ -4191,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);
@@ -4206,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);
@@ -4359,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
@@ -4381,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) {
@@ -4476,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 =
@@ -4492,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;
}
/*
@@ -4699,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 3e549b8ec8c9..85f5db95c60f 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -15,8 +15,10 @@ ifeq ($(CONFIG_X86_32),y)
obj-y += atomic64_32.o
lib-y += checksum_32.o
lib-y += strstr_32.o
- lib-y += semaphore_32.o string_32.o cmpxchg8b_emu.o
-
+ lib-y += semaphore_32.o string_32.o
+ifneq ($(CONFIG_X86_CMPXCHG64),y)
+ lib-y += cmpxchg8b_emu.o
+endif
lib-$(CONFIG_X86_USE_3DNOW) += mmx_32.o
else
obj-y += io_64.o iomap_copy_64.o
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile
index d49202e740ea..56d917b556c6 100644
--- a/arch/x86/pci/Makefile
+++ b/arch/x86/pci/Makefile
@@ -15,3 +15,4 @@ 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
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..fbeec31316cf 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;
@@ -426,11 +424,11 @@ int __init pcibios_init(void)
* and P4. 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;
+ pci_dfl_cache_line_size = 32 >> 2;
if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD)
- pci_cache_line_size = 64 >> 2; /* K7 & K8 */
+ pci_dfl_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 */
+ pci_dfl_cache_line_size = 128 >> 2; /* P4 */
pcibios_resource_survey();
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/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/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index 19085ff0484a..19f7df30937f 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -13,6 +13,7 @@
*/
#include <linux/errno.h>
+#include <linux/sched.h>
#include <linux/time.h>
#include <linux/clocksource.h>
#include <linux/interrupt.h>
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/blk-core.c b/block/blk-core.c
index 81f34311659a..ac0fa10f8fa5 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -70,7 +70,7 @@ static void drive_stat_acct(struct request *rq, int new_io)
part_stat_inc(cpu, part, merges[rw]);
else {
part_round_stats(cpu, part);
- part_inc_in_flight(part);
+ part_inc_in_flight(part, rw);
}
part_stat_unlock();
@@ -1030,9 +1030,9 @@ static void part_round_stats_single(int cpu, struct hd_struct *part,
if (now == part->stamp)
return;
- if (part->in_flight) {
+ if (part_in_flight(part)) {
__part_stat_add(cpu, part, time_in_queue,
- part->in_flight * (now - part->stamp));
+ part_in_flight(part) * (now - part->stamp));
__part_stat_add(cpu, part, io_ticks, (now - part->stamp));
}
part->stamp = now;
@@ -1739,7 +1739,7 @@ static void blk_account_io_done(struct request *req)
part_stat_inc(cpu, part, ios[rw]);
part_stat_add(cpu, part, ticks[rw], duration);
part_round_stats(cpu, part);
- part_dec_in_flight(part);
+ part_dec_in_flight(part, rw);
part_stat_unlock();
}
@@ -2492,14 +2492,6 @@ int kblockd_schedule_work(struct request_queue *q, struct work_struct *work)
}
EXPORT_SYMBOL(kblockd_schedule_work);
-int kblockd_schedule_delayed_work(struct request_queue *q,
- struct delayed_work *work,
- unsigned long delay)
-{
- return queue_delayed_work(kblockd_workqueue, work, delay);
-}
-EXPORT_SYMBOL(kblockd_schedule_delayed_work);
-
int __init blk_dev_init(void)
{
BUILD_BUG_ON(__REQ_NR_BITS > 8 *
diff --git a/block/blk-merge.c b/block/blk-merge.c
index b0de8574fdc8..99cb5cf1f447 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -351,7 +351,7 @@ static void blk_account_io_merge(struct request *req)
part = disk_map_sector_rcu(req->rq_disk, blk_rq_pos(req));
part_round_stats(cpu, part);
- part_dec_in_flight(part);
+ part_dec_in_flight(part, rq_data_dir(req));
part_stat_unlock();
}
diff --git a/block/blk-settings.c b/block/blk-settings.c
index e0695bca7027..66d4aa8799b7 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -242,7 +242,7 @@ EXPORT_SYMBOL(blk_queue_max_hw_sectors);
/**
* blk_queue_max_discard_sectors - set max sectors for a single discard
* @q: the request queue for the device
- * @max_discard: maximum number of sectors to discard
+ * @max_discard_sectors: maximum number of sectors to discard
**/
void blk_queue_max_discard_sectors(struct request_queue *q,
unsigned int max_discard_sectors)
diff --git a/block/blk-tag.c b/block/blk-tag.c
index 2e5cfeb59333..6b0f52c20964 100644
--- a/block/blk-tag.c
+++ b/block/blk-tag.c
@@ -359,7 +359,7 @@ int blk_queue_start_tag(struct request_queue *q, struct request *rq)
max_depth -= 2;
if (!max_depth)
max_depth = 1;
- if (q->in_flight[0] > max_depth)
+ if (q->in_flight[BLK_RW_ASYNC] > max_depth)
return 1;
}
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 9c4b679908f4..069a61017c02 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -150,7 +150,7 @@ struct cfq_data {
* idle window management
*/
struct timer_list idle_slice_timer;
- struct delayed_work unplug_work;
+ struct work_struct unplug_work;
struct cfq_queue *active_queue;
struct cfq_io_context *active_cic;
@@ -230,7 +230,7 @@ CFQ_CFQQ_FNS(coop);
blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args)
static void cfq_dispatch_insert(struct request_queue *, struct request *);
-static struct cfq_queue *cfq_get_queue(struct cfq_data *, int,
+static struct cfq_queue *cfq_get_queue(struct cfq_data *, bool,
struct io_context *, gfp_t);
static struct cfq_io_context *cfq_cic_lookup(struct cfq_data *,
struct io_context *);
@@ -241,40 +241,35 @@ static inline int rq_in_driver(struct cfq_data *cfqd)
}
static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
- int is_sync)
+ bool is_sync)
{
- return cic->cfqq[!!is_sync];
+ return cic->cfqq[is_sync];
}
static inline void cic_set_cfqq(struct cfq_io_context *cic,
- struct cfq_queue *cfqq, int is_sync)
+ struct cfq_queue *cfqq, bool is_sync)
{
- cic->cfqq[!!is_sync] = cfqq;
+ cic->cfqq[is_sync] = cfqq;
}
/*
* We regard a request as SYNC, if it's either a read or has the SYNC bit
* set (in which case it could also be direct WRITE).
*/
-static inline int cfq_bio_sync(struct bio *bio)
+static inline bool cfq_bio_sync(struct bio *bio)
{
- if (bio_data_dir(bio) == READ || bio_rw_flagged(bio, BIO_RW_SYNCIO))
- return 1;
-
- return 0;
+ return bio_data_dir(bio) == READ || bio_rw_flagged(bio, BIO_RW_SYNCIO);
}
/*
* scheduler run of queue, if there are requests pending and no one in the
* driver that will restart queueing
*/
-static inline void cfq_schedule_dispatch(struct cfq_data *cfqd,
- unsigned long delay)
+static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
{
if (cfqd->busy_queues) {
cfq_log(cfqd, "schedule dispatch");
- kblockd_schedule_delayed_work(cfqd->queue, &cfqd->unplug_work,
- delay);
+ kblockd_schedule_work(cfqd->queue, &cfqd->unplug_work);
}
}
@@ -290,7 +285,7 @@ static int cfq_queue_empty(struct request_queue *q)
* if a queue is marked sync and has sync io queued. A sync queue with async
* io only, should not get full sync slice length.
*/
-static inline int cfq_prio_slice(struct cfq_data *cfqd, int sync,
+static inline int cfq_prio_slice(struct cfq_data *cfqd, bool sync,
unsigned short prio)
{
const int base_slice = cfqd->cfq_slice[sync];
@@ -318,7 +313,7 @@ cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
* isn't valid until the first request from the dispatch is activated
* and the slice time set.
*/
-static inline int cfq_slice_used(struct cfq_queue *cfqq)
+static inline bool cfq_slice_used(struct cfq_queue *cfqq)
{
if (cfq_cfqq_slice_new(cfqq))
return 0;
@@ -493,7 +488,7 @@ static unsigned long cfq_slice_offset(struct cfq_data *cfqd,
* we will service the queues.
*/
static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
- int add_front)
+ bool add_front)
{
struct rb_node **p, *parent;
struct cfq_queue *__cfqq;
@@ -509,11 +504,20 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
} else
rb_key += jiffies;
} else if (!add_front) {
+ /*
+ * Get our rb key offset. Subtract any residual slice
+ * value carried from last service. A negative resid
+ * count indicates slice overrun, and this should position
+ * the next service time further away in the tree.
+ */
rb_key = cfq_slice_offset(cfqd, cfqq) + jiffies;
- rb_key += cfqq->slice_resid;
+ rb_key -= cfqq->slice_resid;
cfqq->slice_resid = 0;
- } else
- rb_key = 0;
+ } else {
+ rb_key = -HZ;
+ __cfqq = cfq_rb_first(&cfqd->service_tree);
+ rb_key += __cfqq ? __cfqq->rb_key : jiffies;
+ }
if (!RB_EMPTY_NODE(&cfqq->rb_node)) {
/*
@@ -547,7 +551,7 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq,
n = &(*p)->rb_left;
else if (cfq_class_idle(cfqq) > cfq_class_idle(__cfqq))
n = &(*p)->rb_right;
- else if (rb_key < __cfqq->rb_key)
+ else if (time_before(rb_key, __cfqq->rb_key))
n = &(*p)->rb_left;
else
n = &(*p)->rb_right;
@@ -827,8 +831,10 @@ cfq_merged_requests(struct request_queue *q, struct request *rq,
* reposition in fifo if next is older than rq
*/
if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist) &&
- time_before(next->start_time, rq->start_time))
+ time_before(rq_fifo_time(next), rq_fifo_time(rq))) {
list_move(&rq->queuelist, &next->queuelist);
+ rq_set_fifo_time(rq, rq_fifo_time(next));
+ }
cfq_remove_request(next);
}
@@ -844,7 +850,7 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
* Disallow merge of a sync bio into an async request.
*/
if (cfq_bio_sync(bio) && !rq_is_sync(rq))
- return 0;
+ return false;
/*
* Lookup the cfqq that this bio will be queued with. Allow
@@ -852,13 +858,10 @@ static int cfq_allow_merge(struct request_queue *q, struct request *rq,
*/
cic = cfq_cic_lookup(cfqd, current->io_context);
if (!cic)
- return 0;
+ return false;
cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
- if (cfqq == RQ_CFQQ(rq))
- return 1;
-
- return 0;
+ return cfqq == RQ_CFQQ(rq);
}
static void __cfq_set_active_queue(struct cfq_data *cfqd,
@@ -886,7 +889,7 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd,
*/
static void
__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
- int timed_out)
+ bool timed_out)
{
cfq_log_cfqq(cfqd, cfqq, "slice expired t=%d", timed_out);
@@ -914,7 +917,7 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
}
}
-static inline void cfq_slice_expired(struct cfq_data *cfqd, int timed_out)
+static inline void cfq_slice_expired(struct cfq_data *cfqd, bool timed_out)
{
struct cfq_queue *cfqq = cfqd->active_queue;
@@ -1026,7 +1029,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd,
*/
static struct cfq_queue *cfq_close_cooperator(struct cfq_data *cfqd,
struct cfq_queue *cur_cfqq,
- int probe)
+ bool probe)
{
struct cfq_queue *cfqq;
@@ -1090,6 +1093,15 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
if (!cic || !atomic_read(&cic->ioc->nr_tasks))
return;
+ /*
+ * If our average think time is larger than the remaining time
+ * slice, then don't idle. This avoids overrunning the allotted
+ * time slice.
+ */
+ if (sample_valid(cic->ttime_samples) &&
+ (cfqq->slice_end - jiffies < cic->ttime_mean))
+ return;
+
cfq_mark_cfqq_wait_request(cfqq);
/*
@@ -1129,9 +1141,7 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq)
*/
static struct request *cfq_check_fifo(struct cfq_queue *cfqq)
{
- struct cfq_data *cfqd = cfqq->cfqd;
- struct request *rq;
- int fifo;
+ struct request *rq = NULL;
if (cfq_cfqq_fifo_expire(cfqq))
return NULL;
@@ -1141,13 +1151,11 @@ static struct request *cfq_check_fifo(struct cfq_queue *cfqq)
if (list_empty(&cfqq->fifo))
return NULL;
- fifo = cfq_cfqq_sync(cfqq);
rq = rq_entry_fifo(cfqq->fifo.next);
-
- if (time_before(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo]))
+ if (time_before(jiffies, rq_fifo_time(rq)))
rq = NULL;
- cfq_log_cfqq(cfqd, cfqq, "fifo=%p", rq);
+ cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq);
return rq;
}
@@ -1248,67 +1256,21 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd)
return dispatched;
}
-/*
- * Dispatch a request from cfqq, moving them to the request queue
- * dispatch list.
- */
-static void cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
- struct request *rq;
-
- BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list));
-
- /*
- * follow expired path, else get first next available
- */
- rq = cfq_check_fifo(cfqq);
- if (!rq)
- rq = cfqq->next_rq;
-
- /*
- * insert request into driver dispatch list
- */
- cfq_dispatch_insert(cfqd->queue, rq);
-
- if (!cfqd->active_cic) {
- struct cfq_io_context *cic = RQ_CIC(rq);
-
- atomic_long_inc(&cic->ioc->refcount);
- cfqd->active_cic = cic;
- }
-}
-
-/*
- * Find the cfqq that we need to service and move a request from that to the
- * dispatch list
- */
-static int cfq_dispatch_requests(struct request_queue *q, int force)
-{
- struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_queue *cfqq;
unsigned int max_dispatch;
- if (!cfqd->busy_queues)
- return 0;
-
- if (unlikely(force))
- return cfq_forced_dispatch(cfqd);
-
- cfqq = cfq_select_queue(cfqd);
- if (!cfqq)
- return 0;
-
/*
* Drain async requests before we start sync IO
*/
if (cfq_cfqq_idle_window(cfqq) && cfqd->rq_in_driver[BLK_RW_ASYNC])
- return 0;
+ return false;
/*
* If this is an async queue and we have sync IO in flight, let it wait
*/
if (cfqd->sync_flight && !cfq_cfqq_sync(cfqq))
- return 0;
+ return false;
max_dispatch = cfqd->cfq_quantum;
if (cfq_class_idle(cfqq))
@@ -1322,13 +1284,13 @@ static int cfq_dispatch_requests(struct request_queue *q, int force)
* idle queue must always only have a single IO in flight
*/
if (cfq_class_idle(cfqq))
- return 0;
+ return false;
/*
* We have other queues, don't allow more IO from this one
*/
if (cfqd->busy_queues > 1)
- return 0;
+ return false;
/*
* Sole queue user, allow bigger slice
@@ -1352,13 +1314,72 @@ static int cfq_dispatch_requests(struct request_queue *q, int force)
max_dispatch = depth;
}
- if (cfqq->dispatched >= max_dispatch)
+ /*
+ * If we're below the current max, allow a dispatch
+ */
+ return cfqq->dispatched < max_dispatch;
+}
+
+/*
+ * Dispatch a request from cfqq, moving them to the request queue
+ * dispatch list.
+ */
+static bool cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ struct request *rq;
+
+ BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list));
+
+ if (!cfq_may_dispatch(cfqd, cfqq))
+ return false;
+
+ /*
+ * follow expired path, else get first next available
+ */
+ rq = cfq_check_fifo(cfqq);
+ if (!rq)
+ rq = cfqq->next_rq;
+
+ /*
+ * insert request into driver dispatch list
+ */
+ cfq_dispatch_insert(cfqd->queue, rq);
+
+ if (!cfqd->active_cic) {
+ struct cfq_io_context *cic = RQ_CIC(rq);
+
+ atomic_long_inc(&cic->ioc->refcount);
+ cfqd->active_cic = cic;
+ }
+
+ return true;
+}
+
+/*
+ * Find the cfqq that we need to service and move a request from that to the
+ * dispatch list
+ */
+static int cfq_dispatch_requests(struct request_queue *q, int force)
+{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ struct cfq_queue *cfqq;
+
+ if (!cfqd->busy_queues)
+ return 0;
+
+ if (unlikely(force))
+ return cfq_forced_dispatch(cfqd);
+
+ cfqq = cfq_select_queue(cfqd);
+ if (!cfqq)
return 0;
/*
- * Dispatch a request from this cfqq
+ * Dispatch a request from this cfqq, if it is allowed
*/
- cfq_dispatch_request(cfqd, cfqq);
+ if (!cfq_dispatch_request(cfqd, cfqq))
+ return 0;
+
cfqq->slice_dispatch++;
cfq_clear_cfqq_must_dispatch(cfqq);
@@ -1399,7 +1420,7 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
if (unlikely(cfqd->active_queue == cfqq)) {
__cfq_slice_expired(cfqd, cfqq, 0);
- cfq_schedule_dispatch(cfqd, 0);
+ cfq_schedule_dispatch(cfqd);
}
kmem_cache_free(cfq_pool, cfqq);
@@ -1494,7 +1515,7 @@ static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
if (unlikely(cfqq == cfqd->active_queue)) {
__cfq_slice_expired(cfqd, cfqq, 0);
- cfq_schedule_dispatch(cfqd, 0);
+ cfq_schedule_dispatch(cfqd);
}
cfq_put_queue(cfqq);
@@ -1658,7 +1679,7 @@ static void cfq_ioc_set_ioprio(struct io_context *ioc)
}
static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
- pid_t pid, int is_sync)
+ pid_t pid, bool is_sync)
{
RB_CLEAR_NODE(&cfqq->rb_node);
RB_CLEAR_NODE(&cfqq->p_node);
@@ -1678,7 +1699,7 @@ static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
}
static struct cfq_queue *
-cfq_find_alloc_queue(struct cfq_data *cfqd, int is_sync,
+cfq_find_alloc_queue(struct cfq_data *cfqd, bool is_sync,
struct io_context *ioc, gfp_t gfp_mask)
{
struct cfq_queue *cfqq, *new_cfqq = NULL;
@@ -1742,7 +1763,7 @@ cfq_async_queue_prio(struct cfq_data *cfqd, int ioprio_class, int ioprio)
}
static struct cfq_queue *
-cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct io_context *ioc,
+cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct io_context *ioc,
gfp_t gfp_mask)
{
const int ioprio = task_ioprio(ioc);
@@ -1977,7 +1998,10 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
(!cfqd->cfq_latency && cfqd->hw_tag && CIC_SEEKY(cic)))
enable_idle = 0;
else if (sample_valid(cic->ttime_samples)) {
- if (cic->ttime_mean > cfqd->cfq_slice_idle)
+ unsigned int slice_idle = cfqd->cfq_slice_idle;
+ if (sample_valid(cic->seek_samples) && CIC_SEEKY(cic))
+ slice_idle = msecs_to_jiffies(CFQ_MIN_TT);
+ if (cic->ttime_mean > slice_idle)
enable_idle = 0;
else
enable_idle = 1;
@@ -1996,7 +2020,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
* Check if new_cfqq should preempt the currently active queue. Return 0 for
* no or if we aren't sure, a 1 will cause a preempt.
*/
-static int
+static bool
cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
struct request *rq)
{
@@ -2004,48 +2028,48 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
cfqq = cfqd->active_queue;
if (!cfqq)
- return 0;
+ return false;
if (cfq_slice_used(cfqq))
- return 1;
+ return true;
if (cfq_class_idle(new_cfqq))
- return 0;
+ return false;
if (cfq_class_idle(cfqq))
- return 1;
+ return true;
/*
* if the new request is sync, but the currently running queue is
* not, let the sync request have priority.
*/
if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
- return 1;
+ return true;
/*
* So both queues are sync. Let the new request get disk time if
* it's a metadata request and the current queue is doing regular IO.
*/
if (rq_is_meta(rq) && !cfqq->meta_pending)
- return 1;
+ return false;
/*
* Allow an RT request to pre-empt an ongoing non-RT cfqq timeslice.
*/
if (cfq_class_rt(new_cfqq) && !cfq_class_rt(cfqq))
- return 1;
+ return true;
if (!cfqd->active_cic || !cfq_cfqq_wait_request(cfqq))
- return 0;
+ return false;
/*
* if this request is as-good as one we would expect from the
* current cfqq, let it preempt
*/
if (cfq_rq_close(cfqd, rq))
- return 1;
+ return true;
- return 0;
+ return false;
}
/*
@@ -2130,6 +2154,7 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq)
cfq_add_rq_rb(rq);
+ rq_set_fifo_time(rq, jiffies + cfqd->cfq_fifo_expire[rq_is_sync(rq)]);
list_add_tail(&rq->queuelist, &cfqq->fifo);
cfq_rq_enqueued(cfqd, cfqq, rq);
@@ -2211,7 +2236,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
}
if (!rq_in_driver(cfqd))
- cfq_schedule_dispatch(cfqd, 0);
+ cfq_schedule_dispatch(cfqd);
}
/*
@@ -2309,7 +2334,7 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_io_context *cic;
const int rw = rq_data_dir(rq);
- const int is_sync = rq_is_sync(rq);
+ const bool is_sync = rq_is_sync(rq);
struct cfq_queue *cfqq;
unsigned long flags;
@@ -2341,7 +2366,7 @@ queue_fail:
if (cic)
put_io_context(cic->ioc);
- cfq_schedule_dispatch(cfqd, 0);
+ cfq_schedule_dispatch(cfqd);
spin_unlock_irqrestore(q->queue_lock, flags);
cfq_log(cfqd, "set_request fail");
return 1;
@@ -2350,7 +2375,7 @@ queue_fail:
static void cfq_kick_queue(struct work_struct *work)
{
struct cfq_data *cfqd =
- container_of(work, struct cfq_data, unplug_work.work);
+ container_of(work, struct cfq_data, unplug_work);
struct request_queue *q = cfqd->queue;
spin_lock_irq(q->queue_lock);
@@ -2404,7 +2429,7 @@ static void cfq_idle_slice_timer(unsigned long data)
expire:
cfq_slice_expired(cfqd, timed_out);
out_kick:
- cfq_schedule_dispatch(cfqd, 0);
+ cfq_schedule_dispatch(cfqd);
out_cont:
spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
}
@@ -2412,7 +2437,7 @@ out_cont:
static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
{
del_timer_sync(&cfqd->idle_slice_timer);
- cancel_delayed_work_sync(&cfqd->unplug_work);
+ cancel_work_sync(&cfqd->unplug_work);
}
static void cfq_put_async_queues(struct cfq_data *cfqd)
@@ -2494,7 +2519,7 @@ static void *cfq_init_queue(struct request_queue *q)
cfqd->idle_slice_timer.function = cfq_idle_slice_timer;
cfqd->idle_slice_timer.data = (unsigned long) cfqd;
- INIT_DELAYED_WORK(&cfqd->unplug_work, cfq_kick_queue);
+ INIT_WORK(&cfqd->unplug_work, cfq_kick_queue);
cfqd->cfq_quantum = cfq_quantum;
cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0];
diff --git a/block/elevator.c b/block/elevator.c
index 1975b619c86d..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;
}
@@ -1059,9 +1053,7 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
return count;
strlcpy(elevator_name, name, sizeof(elevator_name));
- strstrip(elevator_name);
-
- e = elevator_get(elevator_name);
+ e = elevator_get(strstrip(elevator_name));
if (!e) {
printk(KERN_ERR "elevator: type %s not found\n", elevator_name);
return -EINVAL;
diff --git a/block/genhd.c b/block/genhd.c
index 5a0861da324d..517e4332cb37 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -869,6 +869,7 @@ static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL);
static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL);
static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
+static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
#ifdef CONFIG_FAIL_MAKE_REQUEST
static struct device_attribute dev_attr_fail =
__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
@@ -888,6 +889,7 @@ static struct attribute *disk_attrs[] = {
&dev_attr_alignment_offset.attr,
&dev_attr_capability.attr,
&dev_attr_stat.attr,
+ &dev_attr_inflight.attr,
#ifdef CONFIG_FAIL_MAKE_REQUEST
&dev_attr_fail.attr,
#endif
@@ -1053,7 +1055,7 @@ static int diskstats_show(struct seq_file *seqf, void *v)
part_stat_read(hd, merges[1]),
(unsigned long long)part_stat_read(hd, sectors[1]),
jiffies_to_msecs(part_stat_read(hd, ticks[1])),
- hd->in_flight,
+ part_in_flight(hd),
jiffies_to_msecs(part_stat_read(hd, io_ticks)),
jiffies_to_msecs(part_stat_read(hd, time_in_queue))
);
diff --git a/crypto/aead.c b/crypto/aead.c
index d9aa733db164..0a55da70845e 100644
--- a/crypto/aead.c
+++ b/crypto/aead.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/rtnetlink.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/seq_file.h>
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/Kconfig b/drivers/acpi/Kconfig
index 0ed42d8870c7..93d2c7971df6 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -218,10 +218,10 @@ config ACPI_PROCESSOR_AGGREGATOR
depends on X86
help
ACPI 4.0 defines processor Aggregator, which enables OS to perform
- specfic processor configuration and control that applies to all
+ specific processor configuration and control that applies to all
processors in the platform. Currently only logical processor idling
is defined, which is to reduce power consumption. This driver
- support the new device.
+ supports the new device.
config ACPI_THERMAL
tristate "Thermal Zone"
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 98b9690b0159..b6ed60b57b0d 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -245,6 +245,7 @@ static void acpi_ac_notify(struct acpi_device *device, u32 event)
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event,
(u32) ac->state);
+ acpi_notifier_call_chain(device, event, (u32) ac->state);
#ifdef CONFIG_ACPI_SYSFS_POWER
kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE);
#endif
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/button.c b/drivers/acpi/button.c
index 9335b87c5174..0c9c6a9a002c 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -251,6 +251,9 @@ int acpi_lid_open(void)
acpi_status status;
unsigned long long state;
+ if (!lid_device)
+ return -ENODEV;
+
status = acpi_evaluate_integer(lid_device->handle, "_LID", NULL,
&state);
if (ACPI_FAILURE(status))
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 31122214e0ec..1af808171d46 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -389,6 +389,17 @@ struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
pbus = pdev->subordinate;
pci_dev_put(pdev);
+
+ /*
+ * This function may be called for a non-PCI device that has a
+ * PCI parent (eg. a disk under a PCI SATA controller). In that
+ * case pdev->subordinate will be NULL for the parent.
+ */
+ if (!pbus) {
+ dev_dbg(&pdev->dev, "Not a PCI-to-PCI bridge\n");
+ pdev = NULL;
+ break;
+ }
}
out:
list_for_each_entry_safe(node, tmp, &device_list, node)
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index f6e54bf8dd96..64e3c581b7a9 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -1109,7 +1109,12 @@ static int acpi_video_bus_check(struct acpi_video_bus *video)
*/
/* Does this device support video switching? */
- if (video->cap._DOS) {
+ if (video->cap._DOS || video->cap._DOD) {
+ if (!video->cap._DOS) {
+ printk(KERN_WARNING FW_BUG
+ "ACPI(%s) defines _DOD but not _DOS\n",
+ acpi_device_bid(video->device));
+ }
video->flags.multihead = 1;
status = 0;
}
diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c
index 7032f25da9b5..575593a8b4e6 100644
--- a/drivers/acpi/video_detect.c
+++ b/drivers/acpi/video_detect.c
@@ -84,7 +84,7 @@ long acpi_is_video_device(struct acpi_device *device)
return 0;
/* Does this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
+ 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;
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index acd1162712b1..b1a257746a19 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -122,6 +122,7 @@ enum {
HOST_VERSION = 0x10, /* AHCI spec. version compliancy */
HOST_EM_LOC = 0x1c, /* Enclosure Management location */
HOST_EM_CTL = 0x20, /* Enclosure Management Control */
+ HOST_CAP2 = 0x24, /* host capabilities, extended */
/* HOST_CTL bits */
HOST_RESET = (1 << 0), /* reset controller; self-clear */
@@ -129,16 +130,29 @@ enum {
HOST_AHCI_EN = (1 << 31), /* AHCI enabled */
/* HOST_CAP bits */
+ HOST_CAP_SXS = (1 << 5), /* Supports External SATA */
HOST_CAP_EMS = (1 << 6), /* Enclosure Management support */
- HOST_CAP_SSC = (1 << 14), /* Slumber capable */
+ HOST_CAP_CCC = (1 << 7), /* Command Completion Coalescing */
+ HOST_CAP_PART = (1 << 13), /* Partial state capable */
+ HOST_CAP_SSC = (1 << 14), /* Slumber state capable */
+ HOST_CAP_PIO_MULTI = (1 << 15), /* PIO multiple DRQ support */
+ HOST_CAP_FBS = (1 << 16), /* FIS-based switching support */
HOST_CAP_PMP = (1 << 17), /* Port Multiplier support */
+ HOST_CAP_ONLY = (1 << 18), /* Supports AHCI mode only */
HOST_CAP_CLO = (1 << 24), /* Command List Override support */
+ HOST_CAP_LED = (1 << 25), /* Supports activity LED */
HOST_CAP_ALPM = (1 << 26), /* Aggressive Link PM support */
HOST_CAP_SSS = (1 << 27), /* Staggered Spin-up */
+ HOST_CAP_MPS = (1 << 28), /* Mechanical presence switch */
HOST_CAP_SNTF = (1 << 29), /* SNotification register */
HOST_CAP_NCQ = (1 << 30), /* Native Command Queueing */
HOST_CAP_64 = (1 << 31), /* PCI DAC (64-bit DMA) support */
+ /* HOST_CAP2 bits */
+ HOST_CAP2_BOH = (1 << 0), /* BIOS/OS handoff supported */
+ HOST_CAP2_NVMHCI = (1 << 1), /* NVMHCI supported */
+ HOST_CAP2_APST = (1 << 2), /* Automatic partial to slumber */
+
/* registers for each SATA port */
PORT_LST_ADDR = 0x00, /* command list DMA addr */
PORT_LST_ADDR_HI = 0x04, /* command list DMA addr hi */
@@ -267,8 +281,10 @@ struct ahci_em_priv {
struct ahci_host_priv {
unsigned int flags; /* AHCI_HFLAG_* */
u32 cap; /* cap to use */
+ u32 cap2; /* cap2 to use */
u32 port_map; /* port map to use */
u32 saved_cap; /* saved initial cap */
+ u32 saved_cap2; /* saved initial cap2 */
u32 saved_port_map; /* saved initial port_map */
u32 em_loc; /* enclosure management location */
};
@@ -331,12 +347,15 @@ static void ahci_init_sw_activity(struct ata_link *link);
static ssize_t ahci_show_host_caps(struct device *dev,
struct device_attribute *attr, char *buf);
+static ssize_t ahci_show_host_cap2(struct device *dev,
+ struct device_attribute *attr, char *buf);
static ssize_t ahci_show_host_version(struct device *dev,
struct device_attribute *attr, char *buf);
static ssize_t ahci_show_port_cmd(struct device *dev,
struct device_attribute *attr, char *buf);
DEVICE_ATTR(ahci_host_caps, S_IRUGO, ahci_show_host_caps, NULL);
+DEVICE_ATTR(ahci_host_cap2, S_IRUGO, ahci_show_host_cap2, NULL);
DEVICE_ATTR(ahci_host_version, S_IRUGO, ahci_show_host_version, NULL);
DEVICE_ATTR(ahci_port_cmd, S_IRUGO, ahci_show_port_cmd, NULL);
@@ -345,6 +364,7 @@ static struct device_attribute *ahci_shost_attrs[] = {
&dev_attr_em_message_type,
&dev_attr_em_message,
&dev_attr_ahci_host_caps,
+ &dev_attr_ahci_host_cap2,
&dev_attr_ahci_host_version,
&dev_attr_ahci_port_cmd,
NULL
@@ -447,7 +467,8 @@ static const struct ata_port_info ahci_port_info[] = {
[board_ahci_sb600] =
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
- AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255),
+ AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255 |
+ AHCI_HFLAG_32BIT_ONLY),
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
@@ -732,6 +753,16 @@ static ssize_t ahci_show_host_caps(struct device *dev,
return sprintf(buf, "%x\n", hpriv->cap);
}
+static ssize_t ahci_show_host_cap2(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct ata_port *ap = ata_shost_to_port(shost);
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+
+ return sprintf(buf, "%x\n", hpriv->cap2);
+}
+
static ssize_t ahci_show_host_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -771,7 +802,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
struct ahci_host_priv *hpriv)
{
void __iomem *mmio = pcim_iomap_table(pdev)[AHCI_PCI_BAR];
- u32 cap, port_map;
+ u32 cap, cap2, vers, port_map;
int i;
int mv;
@@ -784,6 +815,14 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
hpriv->saved_cap = cap = readl(mmio + HOST_CAP);
hpriv->saved_port_map = port_map = readl(mmio + HOST_PORTS_IMPL);
+ /* CAP2 register is only defined for AHCI 1.2 and later */
+ vers = readl(mmio + HOST_VERSION);
+ if ((vers >> 16) > 1 ||
+ ((vers >> 16) == 1 && (vers & 0xFFFF) >= 0x200))
+ hpriv->saved_cap2 = cap2 = readl(mmio + HOST_CAP2);
+ else
+ hpriv->saved_cap2 = cap2 = 0;
+
/* some chips have errata preventing 64bit use */
if ((cap & HOST_CAP_64) && (hpriv->flags & AHCI_HFLAG_32BIT_ONLY)) {
dev_printk(KERN_INFO, &pdev->dev,
@@ -869,6 +908,7 @@ static void ahci_save_initial_config(struct pci_dev *pdev,
/* record values to use during operation */
hpriv->cap = cap;
+ hpriv->cap2 = cap2;
hpriv->port_map = port_map;
}
@@ -887,6 +927,8 @@ static void ahci_restore_initial_config(struct ata_host *host)
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
writel(hpriv->saved_cap, mmio + HOST_CAP);
+ if (hpriv->saved_cap2)
+ writel(hpriv->saved_cap2, mmio + HOST_CAP2);
writel(hpriv->saved_port_map, mmio + HOST_PORTS_IMPL);
(void) readl(mmio + HOST_PORTS_IMPL); /* flush */
}
@@ -2534,13 +2576,14 @@ static void ahci_print_info(struct ata_host *host)
struct ahci_host_priv *hpriv = host->private_data;
struct pci_dev *pdev = to_pci_dev(host->dev);
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
- u32 vers, cap, impl, speed;
+ u32 vers, cap, cap2, impl, speed;
const char *speed_s;
u16 cc;
const char *scc_s;
vers = readl(mmio + HOST_VERSION);
cap = hpriv->cap;
+ cap2 = hpriv->cap2;
impl = hpriv->port_map;
speed = (cap >> 20) & 0xf;
@@ -2583,25 +2626,29 @@ static void ahci_print_info(struct ata_host *host)
"flags: "
"%s%s%s%s%s%s%s"
"%s%s%s%s%s%s%s"
- "%s\n"
+ "%s%s%s%s%s%s\n"
,
- cap & (1 << 31) ? "64bit " : "",
- cap & (1 << 30) ? "ncq " : "",
- cap & (1 << 29) ? "sntf " : "",
- cap & (1 << 28) ? "ilck " : "",
- cap & (1 << 27) ? "stag " : "",
- cap & (1 << 26) ? "pm " : "",
- cap & (1 << 25) ? "led " : "",
-
- cap & (1 << 24) ? "clo " : "",
- cap & (1 << 19) ? "nz " : "",
- cap & (1 << 18) ? "only " : "",
- cap & (1 << 17) ? "pmp " : "",
- cap & (1 << 15) ? "pio " : "",
- cap & (1 << 14) ? "slum " : "",
- cap & (1 << 13) ? "part " : "",
- cap & (1 << 6) ? "ems ": ""
+ cap & HOST_CAP_64 ? "64bit " : "",
+ cap & HOST_CAP_NCQ ? "ncq " : "",
+ cap & HOST_CAP_SNTF ? "sntf " : "",
+ cap & HOST_CAP_MPS ? "ilck " : "",
+ cap & HOST_CAP_SSS ? "stag " : "",
+ cap & HOST_CAP_ALPM ? "pm " : "",
+ cap & HOST_CAP_LED ? "led " : "",
+ cap & HOST_CAP_CLO ? "clo " : "",
+ cap & HOST_CAP_ONLY ? "only " : "",
+ cap & HOST_CAP_PMP ? "pmp " : "",
+ cap & HOST_CAP_FBS ? "fbs " : "",
+ cap & HOST_CAP_PIO_MULTI ? "pio " : "",
+ cap & HOST_CAP_SSC ? "slum " : "",
+ cap & HOST_CAP_PART ? "part " : "",
+ cap & HOST_CAP_CCC ? "ccc " : "",
+ cap & HOST_CAP_EMS ? "ems " : "",
+ cap & HOST_CAP_SXS ? "sxs " : "",
+ cap2 & HOST_CAP2_APST ? "apst " : "",
+ cap2 & HOST_CAP2_NVMHCI ? "nvmp " : "",
+ cap2 & HOST_CAP2_BOH ? "boh " : ""
);
}
@@ -2650,17 +2697,15 @@ static void ahci_p5wdh_workaround(struct ata_host *host)
}
}
-/*
- * SB600 ahci controller on certain boards can't do 64bit DMA with
- * older BIOS.
- */
-static bool ahci_sb600_32bit_only(struct pci_dev *pdev)
+/* only some SB600 ahci controllers can do 64bit DMA */
+static bool ahci_sb600_enable_64bit(struct pci_dev *pdev)
{
static const struct dmi_system_id sysids[] = {
/*
* The oldest version known to be broken is 0901 and
* working is 1501 which was released on 2007-10-26.
- * Force 32bit DMA on anything older than 1501.
+ * Enable 64bit DMA on 1501 and anything newer.
+ *
* Please read bko#9412 for more info.
*/
{
@@ -2672,48 +2717,29 @@ static bool ahci_sb600_32bit_only(struct pci_dev *pdev)
},
.driver_data = "20071026", /* yyyymmdd */
},
- /*
- * It's yet unknown whether more recent BIOS fixes the
- * problem. Blacklist the whole board for the time
- * being. Please read the following thread for more
- * info.
- *
- * http://thread.gmane.org/gmane.linux.ide/42326
- */
- {
- .ident = "Gigabyte GA-MA69VM-S2",
- .matches = {
- DMI_MATCH(DMI_BOARD_VENDOR,
- "Gigabyte Technology Co., Ltd."),
- DMI_MATCH(DMI_BOARD_NAME, "GA-MA69VM-S2"),
- },
- },
{ }
};
const struct dmi_system_id *match;
+ int year, month, date;
+ char buf[9];
match = dmi_first_match(sysids);
if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
!match)
return false;
- if (match->driver_data) {
- int year, month, date;
- char buf[9];
-
- dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
- snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
-
- if (strcmp(buf, match->driver_data) >= 0)
- return false;
+ dmi_get_date(DMI_BIOS_DATE, &year, &month, &date);
+ snprintf(buf, sizeof(buf), "%04d%02d%02d", year, month, date);
+ if (strcmp(buf, match->driver_data) >= 0) {
+ dev_printk(KERN_WARNING, &pdev->dev, "%s: enabling 64bit DMA\n",
+ match->ident);
+ return true;
+ } else {
dev_printk(KERN_WARNING, &pdev->dev, "%s: BIOS too old, "
"forcing 32bit DMA, update BIOS\n", match->ident);
- } else
- dev_printk(KERN_WARNING, &pdev->dev, "%s: this board can't "
- "do 64bit DMA, forcing 32bit\n", match->ident);
-
- return true;
+ return false;
+ }
}
static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
@@ -2858,6 +2884,55 @@ static bool ahci_broken_online(struct pci_dev *pdev)
return pdev->bus->number == (val >> 8) && pdev->devfn == (val & 0xff);
}
+#ifdef CONFIG_ATA_ACPI
+static void ahci_gtf_filter_workaround(struct ata_host *host)
+{
+ static const struct dmi_system_id sysids[] = {
+ /*
+ * Aspire 3810T issues a bunch of SATA enable commands
+ * via _GTF including an invalid one and one which is
+ * rejected by the device. Among the successful ones
+ * is FPDMA non-zero offset enable which when enabled
+ * only on the drive side leads to NCQ command
+ * failures. Filter it out.
+ */
+ {
+ .ident = "Aspire 3810T",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3810T"),
+ },
+ .driver_data = (void *)ATA_ACPI_FILTER_FPDMA_OFFSET,
+ },
+ { }
+ };
+ const struct dmi_system_id *dmi = dmi_first_match(sysids);
+ unsigned int filter;
+ int i;
+
+ if (!dmi)
+ return;
+
+ filter = (unsigned long)dmi->driver_data;
+ dev_printk(KERN_INFO, host->dev,
+ "applying extra ACPI _GTF filter 0x%x for %s\n",
+ filter, dmi->ident);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap = host->ports[i];
+ struct ata_link *link;
+ struct ata_device *dev;
+
+ ata_for_each_link(link, ap, EDGE)
+ ata_for_each_dev(dev, link, ALL)
+ dev->gtf_filter |= filter;
+ }
+}
+#else
+static inline void ahci_gtf_filter_workaround(struct ata_host *host)
+{}
+#endif
+
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
static int printed_version;
@@ -2926,9 +3001,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
- /* apply sb600 32bit only quirk */
- if (ahci_sb600_32bit_only(pdev))
- hpriv->flags |= AHCI_HFLAG_32BIT_ONLY;
+ /* only some SB600s can do 64bit DMA */
+ if (ahci_sb600_enable_64bit(pdev))
+ hpriv->flags &= ~AHCI_HFLAG_32BIT_ONLY;
if ((hpriv->flags & AHCI_HFLAG_NO_MSI) || pci_enable_msi(pdev))
pci_intx(pdev, 1);
@@ -3023,6 +3098,9 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* apply workaround for ASUS P5W DH Deluxe mainboard */
ahci_p5wdh_workaround(host);
+ /* apply gtf filter quirk */
+ ahci_gtf_filter_workaround(host);
+
/* initialize adapter */
rc = ahci_configure_dma_masks(pdev, hpriv->cap & HOST_CAP_64);
if (rc)
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index 01964b6e6f6b..b0882cddfd4c 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -20,19 +20,9 @@
#include <acpi/acpi_bus.h>
-enum {
- ATA_ACPI_FILTER_SETXFER = 1 << 0,
- ATA_ACPI_FILTER_LOCK = 1 << 1,
- ATA_ACPI_FILTER_DIPM = 1 << 2,
-
- ATA_ACPI_FILTER_DEFAULT = ATA_ACPI_FILTER_SETXFER |
- ATA_ACPI_FILTER_LOCK |
- ATA_ACPI_FILTER_DIPM,
-};
-
-static unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;
+unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;
module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644);
-MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM)");
+MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock, 0x4=DIPM, 0x8=FPDMA non-zero offset, 0x10=FPDMA DMA Setup FIS auto-activate)");
#define NO_PORT_MULT 0xffff
#define SATA_ADR(root, pmp) (((root) << 16) | (pmp))
@@ -613,10 +603,11 @@ static void ata_acpi_gtf_to_tf(struct ata_device *dev,
tf->command = gtf->tf[6]; /* 0x1f7 */
}
-static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
+static int ata_acpi_filter_tf(struct ata_device *dev,
+ const struct ata_taskfile *tf,
const struct ata_taskfile *ptf)
{
- if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_SETXFER) {
+ if (dev->gtf_filter & ATA_ACPI_FILTER_SETXFER) {
/* libata doesn't use ACPI to configure transfer mode.
* It will only confuse device configuration. Skip.
*/
@@ -625,7 +616,7 @@ static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
return 1;
}
- if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_LOCK) {
+ if (dev->gtf_filter & ATA_ACPI_FILTER_LOCK) {
/* BIOS writers, sorry but we don't wanna lock
* features unless the user explicitly said so.
*/
@@ -647,12 +638,23 @@ static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
return 1;
}
- if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_DIPM) {
+ if (tf->command == ATA_CMD_SET_FEATURES &&
+ tf->feature == SETFEATURES_SATA_ENABLE) {
/* inhibit enabling DIPM */
- if (tf->command == ATA_CMD_SET_FEATURES &&
- tf->feature == SETFEATURES_SATA_ENABLE &&
+ if (dev->gtf_filter & ATA_ACPI_FILTER_DIPM &&
tf->nsect == SATA_DIPM)
return 1;
+
+ /* inhibit FPDMA non-zero offset */
+ if (dev->gtf_filter & ATA_ACPI_FILTER_FPDMA_OFFSET &&
+ (tf->nsect == SATA_FPDMA_OFFSET ||
+ tf->nsect == SATA_FPDMA_IN_ORDER))
+ return 1;
+
+ /* inhibit FPDMA auto activation */
+ if (dev->gtf_filter & ATA_ACPI_FILTER_FPDMA_AA &&
+ tf->nsect == SATA_FPDMA_AA)
+ return 1;
}
return 0;
@@ -704,7 +706,7 @@ static int ata_acpi_run_tf(struct ata_device *dev,
pptf = &ptf;
}
- if (!ata_acpi_filter_tf(&tf, pptf)) {
+ if (!ata_acpi_filter_tf(dev, &tf, pptf)) {
rtf = tf;
err_mask = ata_exec_internal(dev, &rtf, NULL,
DMA_NONE, NULL, 0, 0);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 0ddaf43d68c6..b525a0981348 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -5591,6 +5591,9 @@ void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
dev->link = link;
dev->devno = dev - link->device;
+#ifdef CONFIG_ATA_ACPI
+ dev->gtf_filter = ata_acpi_gtf_filter;
+#endif
ata_dev_init(dev);
}
}
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index a04488f0de88..0a97822da211 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -2667,14 +2667,14 @@ int ata_eh_reset(struct ata_link *link, int classify,
dev->pio_mode = XFER_PIO_0;
dev->flags &= ~ATA_DFLAG_SLEEPING;
- if (!ata_phys_link_offline(ata_dev_phys_link(dev))) {
- /* apply class override */
- if (lflags & ATA_LFLAG_ASSUME_ATA)
- classes[dev->devno] = ATA_DEV_ATA;
- else if (lflags & ATA_LFLAG_ASSUME_SEMB)
- classes[dev->devno] = ATA_DEV_SEMB_UNSUP;
- } else
- classes[dev->devno] = ATA_DEV_NONE;
+ if (ata_phys_link_offline(ata_dev_phys_link(dev)))
+ continue;
+
+ /* apply class override */
+ if (lflags & ATA_LFLAG_ASSUME_ATA)
+ classes[dev->devno] = ATA_DEV_ATA;
+ else if (lflags & ATA_LFLAG_ASSUME_SEMB)
+ classes[dev->devno] = ATA_DEV_SEMB_UNSUP;
}
/* record current link speed */
@@ -2713,34 +2713,48 @@ int ata_eh_reset(struct ata_link *link, int classify,
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
spin_unlock_irqrestore(link->ap->lock, flags);
- /* Make sure onlineness and classification result correspond.
+ /*
+ * Make sure onlineness and classification result correspond.
* Hotplug could have happened during reset and some
* controllers fail to wait while a drive is spinning up after
* being hotplugged causing misdetection. By cross checking
- * link onlineness and classification result, those conditions
- * can be reliably detected and retried.
+ * link on/offlineness and classification result, those
+ * conditions can be reliably detected and retried.
*/
nr_unknown = 0;
ata_for_each_dev(dev, link, ALL) {
- /* convert all ATA_DEV_UNKNOWN to ATA_DEV_NONE */
- if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
- classes[dev->devno] = ATA_DEV_NONE;
- if (ata_phys_link_online(ata_dev_phys_link(dev)))
+ if (ata_phys_link_online(ata_dev_phys_link(dev))) {
+ if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
+ ata_dev_printk(dev, KERN_DEBUG, "link online "
+ "but device misclassifed\n");
+ classes[dev->devno] = ATA_DEV_NONE;
nr_unknown++;
+ }
+ } else if (ata_phys_link_offline(ata_dev_phys_link(dev))) {
+ if (ata_class_enabled(classes[dev->devno]))
+ ata_dev_printk(dev, KERN_DEBUG, "link offline, "
+ "clearing class %d to NONE\n",
+ classes[dev->devno]);
+ classes[dev->devno] = ATA_DEV_NONE;
+ } else if (classes[dev->devno] == ATA_DEV_UNKNOWN) {
+ ata_dev_printk(dev, KERN_DEBUG, "link status unknown, "
+ "clearing UNKNOWN to NONE\n");
+ classes[dev->devno] = ATA_DEV_NONE;
}
}
if (classify && nr_unknown) {
if (try < max_tries) {
ata_link_printk(link, KERN_WARNING, "link online but "
- "device misclassified, retrying\n");
+ "%d devices misclassified, retrying\n",
+ nr_unknown);
failed_link = link;
rc = -EAGAIN;
goto fail;
}
ata_link_printk(link, KERN_WARNING,
- "link online but device misclassified, "
- "device detection might fail\n");
+ "link online but %d devices misclassified, "
+ "device detection might fail\n", nr_unknown);
}
/* reset successful, schedule revalidation */
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index be8e2628f82c..823e63096362 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -118,6 +118,8 @@ extern void ata_lpm_schedule(struct ata_port *ap, enum link_pm);
/* libata-acpi.c */
#ifdef CONFIG_ATA_ACPI
+extern unsigned int ata_acpi_gtf_filter;
+
extern void ata_acpi_associate_sata_port(struct ata_port *ap);
extern void ata_acpi_associate(struct ata_host *host);
extern void ata_acpi_dissociate(struct ata_host *host);
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index fc9c5d6d7d80..1432dc9d0ab8 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -290,7 +290,7 @@ static void ali_warn_atapi_dma(struct ata_device *adev)
if (print_info && adev->class == ATA_DEV_ATAPI && !ali_atapi_dma) {
ata_dev_printk(adev, KERN_WARNING,
- "WARNING: ATAPI DMA disabled for reliablity issues. It can be enabled\n");
+ "WARNING: ATAPI DMA disabled for reliability issues. It can be enabled\n");
ata_dev_printk(adev, KERN_WARNING,
"WARNING: via pata_ali.atapi_dma modparam or corresponding sysfs node.\n");
}
diff --git a/drivers/ata/pata_atp867x.c b/drivers/ata/pata_atp867x.c
index 7990de925d2e..6fe7ded40c6a 100644
--- a/drivers/ata/pata_atp867x.c
+++ b/drivers/ata/pata_atp867x.c
@@ -118,20 +118,13 @@ struct atp867x_priv {
int pci66mhz;
};
-static inline u8 atp867x_speed_to_mode(u8 speed)
-{
- return speed - XFER_UDMA_0 + 1;
-}
-
static void atp867x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
struct atp867x_priv *dp = ap->private_data;
u8 speed = adev->dma_mode;
u8 b;
- u8 mode;
-
- mode = atp867x_speed_to_mode(speed);
+ u8 mode = speed - XFER_UDMA_0 + 1;
/*
* Doc 6.6.9: decrease the udma mode value by 1 for safer UDMA speed
@@ -156,25 +149,38 @@ static void atp867x_set_dmamode(struct ata_port *ap, struct ata_device *adev)
iowrite8(b, dp->dma_mode);
}
-static int atp867x_get_active_clocks_shifted(unsigned int clk)
+static int atp867x_get_active_clocks_shifted(struct ata_port *ap,
+ unsigned int clk)
{
+ struct atp867x_priv *dp = ap->private_data;
unsigned char clocks = clk;
+ /*
+ * Doc 6.6.9: increase the clock value by 1 for safer PIO speed
+ * on 66MHz bus
+ */
+ if (dp->pci66mhz)
+ clocks++;
+
switch (clocks) {
case 0:
clocks = 1;
break;
- case 1 ... 7:
- break;
- case 8 ... 12:
- clocks = 7;
+ case 1 ... 6:
break;
default:
printk(KERN_WARNING "ATP867X: active %dclk is invalid. "
- "Using default 8clk.\n", clk);
- clocks = 0; /* 8 clk */
+ "Using 12clk.\n", clk);
+ case 9 ... 12:
+ clocks = 7; /* 12 clk */
break;
+ case 7:
+ case 8: /* default 8 clk */
+ clocks = 0;
+ goto active_clock_shift_done;
}
+
+active_clock_shift_done:
return clocks << ATP867X_IO_PIOSPD_ACTIVE_SHIFT;
}
@@ -188,20 +194,20 @@ static int atp867x_get_recover_clocks_shifted(unsigned int clk)
break;
case 1 ... 11:
break;
- case 12:
- clocks = 0;
- break;
- case 13: case 14:
- --clocks;
+ case 13:
+ case 14:
+ --clocks; /* by the spec */
break;
case 15:
break;
default:
printk(KERN_WARNING "ATP867X: recover %dclk is invalid. "
- "Using default 15clk.\n", clk);
- clocks = 0; /* 12 clk */
+ "Using default 12clk.\n", clk);
+ case 12: /* default 12 clk */
+ clocks = 0;
break;
}
+
return clocks << ATP867X_IO_PIOSPD_RECOVER_SHIFT;
}
@@ -230,25 +236,38 @@ static void atp867x_set_piomode(struct ata_port *ap, struct ata_device *adev)
b = (b & ~ATP867X_IO_DMAMODE_MSTR_MASK);
iowrite8(b, dp->dma_mode);
- b = atp867x_get_active_clocks_shifted(t.active) |
- atp867x_get_recover_clocks_shifted(t.recover);
- if (dp->pci66mhz)
- b += 0x10;
+ b = atp867x_get_active_clocks_shifted(ap, t.active) |
+ atp867x_get_recover_clocks_shifted(t.recover);
if (adev->devno & 1)
iowrite8(b, dp->slave_piospd);
else
iowrite8(b, dp->mstr_piospd);
- /*
- * use the same value for comand timing as for PIO timimg
- */
+ b = atp867x_get_active_clocks_shifted(ap, t.act8b) |
+ atp867x_get_recover_clocks_shifted(t.rec8b);
+
iowrite8(b, dp->eightb_piospd);
}
+static int atp867x_cable_override(struct pci_dev *pdev)
+{
+ if (pdev->subsystem_vendor == PCI_VENDOR_ID_ARTOP &&
+ (pdev->subsystem_device == PCI_DEVICE_ID_ARTOP_ATP867A ||
+ pdev->subsystem_device == PCI_DEVICE_ID_ARTOP_ATP867B)) {
+ return 1;
+ }
+ return 0;
+}
+
static int atp867x_cable_detect(struct ata_port *ap)
{
- return ATA_CBL_PATA40_SHORT;
+ struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+
+ if (atp867x_cable_override(pdev))
+ return ATA_CBL_PATA40_SHORT;
+
+ return ATA_CBL_PATA_UNK;
}
static struct scsi_host_template atp867x_sht = {
@@ -471,7 +490,6 @@ static int atp867x_init_one(struct pci_dev *pdev,
static const struct ata_port_info info_867x = {
.flags = ATA_FLAG_SLAVE_POSS,
.pio_mask = ATA_PIO4,
- .mwdma_mask = ATA_MWDMA2,
.udma_mask = ATA_UDMA6,
.port_ops = &atp867x_ops,
};
@@ -515,6 +533,23 @@ err_out:
return rc;
}
+#ifdef CONFIG_PM
+static int atp867x_reinit_one(struct pci_dev *pdev)
+{
+ struct ata_host *host = dev_get_drvdata(&pdev->dev);
+ int rc;
+
+ rc = ata_pci_device_do_resume(pdev);
+ if (rc)
+ return rc;
+
+ atp867x_fixup(host);
+
+ ata_host_resume(host);
+ return 0;
+}
+#endif
+
static struct pci_device_id atp867x_pci_tbl[] = {
{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP867A), 0 },
{ PCI_VDEVICE(ARTOP, PCI_DEVICE_ID_ARTOP_ATP867B), 0 },
@@ -526,6 +561,10 @@ static struct pci_driver atp867x_driver = {
.id_table = atp867x_pci_tbl,
.probe = atp867x_init_one,
.remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = atp867x_reinit_one,
+#endif
};
static int __init atp867x_init(void)
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/cciss.c b/drivers/block/cciss.c
index fb5be2d95d52..6399e5090df4 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -68,6 +68,12 @@ MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
MODULE_VERSION("3.6.20");
MODULE_LICENSE("GPL");
+static int cciss_allow_hpsa;
+module_param(cciss_allow_hpsa, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(cciss_allow_hpsa,
+ "Prevent cciss driver from accessing hardware known to be "
+ " supported by the hpsa driver");
+
#include "cciss_cmd.h"
#include "cciss.h"
#include <linux/cciss_ioctl.h>
@@ -101,8 +107,6 @@ static const struct pci_device_id cciss_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324A},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324B},
- {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
- PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0},
{0,}
};
@@ -123,8 +127,6 @@ static struct board_type products[] = {
{0x409D0E11, "Smart Array 6400 EM", &SA5_access},
{0x40910E11, "Smart Array 6i", &SA5_access},
{0x3225103C, "Smart Array P600", &SA5_access},
- {0x3223103C, "Smart Array P800", &SA5_access},
- {0x3234103C, "Smart Array P400", &SA5_access},
{0x3235103C, "Smart Array P400i", &SA5_access},
{0x3211103C, "Smart Array E200i", &SA5_access},
{0x3212103C, "Smart Array E200", &SA5_access},
@@ -132,6 +134,10 @@ static struct board_type products[] = {
{0x3214103C, "Smart Array E200i", &SA5_access},
{0x3215103C, "Smart Array E200i", &SA5_access},
{0x3237103C, "Smart Array E500", &SA5_access},
+/* controllers below this line are also supported by the hpsa driver. */
+#define HPSA_BOUNDARY 0x3223103C
+ {0x3223103C, "Smart Array P800", &SA5_access},
+ {0x3234103C, "Smart Array P400", &SA5_access},
{0x323D103C, "Smart Array P700m", &SA5_access},
{0x3241103C, "Smart Array P212", &SA5_access},
{0x3243103C, "Smart Array P410", &SA5_access},
@@ -140,7 +146,6 @@ static struct board_type products[] = {
{0x3249103C, "Smart Array P812", &SA5_access},
{0x324A103C, "Smart Array P712m", &SA5_access},
{0x324B103C, "Smart Array P711m", &SA5_access},
- {0xFFFF103C, "Unknown Smart Array", &SA5_access},
};
/* How long to wait (in milliseconds) for board to go into simple mode */
@@ -3754,7 +3759,27 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
__u64 cfg_offset;
__u32 cfg_base_addr;
__u64 cfg_base_addr_index;
- int i, err;
+ int i, prod_index, err;
+
+ subsystem_vendor_id = pdev->subsystem_vendor;
+ subsystem_device_id = pdev->subsystem_device;
+ board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) |
+ subsystem_vendor_id);
+
+ for (i = 0; i < ARRAY_SIZE(products); i++) {
+ /* Stand aside for hpsa driver on request */
+ if (cciss_allow_hpsa && products[i].board_id == HPSA_BOUNDARY)
+ return -ENODEV;
+ if (board_id == products[i].board_id)
+ break;
+ }
+ prod_index = i;
+ if (prod_index == ARRAY_SIZE(products)) {
+ dev_warn(&pdev->dev,
+ "unrecognized board ID: 0x%08lx, ignoring.\n",
+ (unsigned long) board_id);
+ return -ENODEV;
+ }
/* check to see if controller has been disabled */
/* BEFORE trying to enable it */
@@ -3778,11 +3803,6 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
return err;
}
- subsystem_vendor_id = pdev->subsystem_vendor;
- subsystem_device_id = pdev->subsystem_device;
- board_id = (((__u32) (subsystem_device_id << 16) & 0xffff0000) |
- subsystem_vendor_id);
-
#ifdef CCISS_DEBUG
printk("command = %x\n", command);
printk("irq = %x\n", pdev->irq);
@@ -3868,14 +3888,9 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
* leave a little room for ioctl calls.
*/
c->max_commands = readl(&(c->cfgtable->CmdsOutMax));
- for (i = 0; i < ARRAY_SIZE(products); i++) {
- if (board_id == products[i].board_id) {
- c->product_name = products[i].product_name;
- c->access = *(products[i].access);
- c->nr_cmds = c->max_commands - 4;
- break;
- }
- }
+ c->product_name = products[prod_index].product_name;
+ c->access = *(products[prod_index].access);
+ c->nr_cmds = c->max_commands - 4;
if ((readb(&c->cfgtable->Signature[0]) != 'C') ||
(readb(&c->cfgtable->Signature[1]) != 'I') ||
(readb(&c->cfgtable->Signature[2]) != 'S') ||
@@ -3884,27 +3899,6 @@ static int __devinit cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
err = -ENODEV;
goto err_out_free_res;
}
- /* We didn't find the controller in our list. We know the
- * signature is valid. If it's an HP device let's try to
- * bind to the device and fire it up. Otherwise we bail.
- */
- if (i == ARRAY_SIZE(products)) {
- if (subsystem_vendor_id == PCI_VENDOR_ID_HP) {
- c->product_name = products[i-1].product_name;
- c->access = *(products[i-1].access);
- c->nr_cmds = c->max_commands - 4;
- printk(KERN_WARNING "cciss: This is an unknown "
- "Smart Array controller.\n"
- "cciss: Please update to the latest driver "
- "available from www.hp.com.\n");
- } else {
- printk(KERN_WARNING "cciss: Sorry, I don't know how"
- " to access the Smart Array controller %08lx\n"
- , (unsigned long)board_id);
- err = -ENODEV;
- goto err_out_free_res;
- }
- }
#ifdef CONFIG_X86
{
/* Need to enable prefetch in the SCSI core for 6400 in x86 */
@@ -4254,7 +4248,7 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
mutex_init(&hba[i]->busy_shutting_down);
if (cciss_pci_init(hba[i], pdev) != 0)
- goto clean0;
+ goto clean_no_release_regions;
sprintf(hba[i]->devname, "cciss%d", i);
hba[i]->ctlr = i;
@@ -4391,13 +4385,14 @@ clean2:
clean1:
cciss_destroy_hba_sysfs_entry(hba[i]);
clean0:
+ pci_release_regions(pdev);
+clean_no_release_regions:
hba[i]->busy_initializing = 0;
/*
* Deliberately omit pci_disable_device(): it does something nasty to
* Smart Array controllers that pci_enable_device does not undo
*/
- pci_release_regions(pdev);
pci_set_drvdata(pdev, NULL);
free_hba(i);
return -1;
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_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/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/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index 60ab75104da9..1c129211302d 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -217,7 +217,7 @@ static const struct agp_bridge_driver parisc_agp_driver = {
.configure = parisc_agp_configure,
.fetch_size = parisc_agp_fetch_size,
.tlb_flush = parisc_agp_tlbflush,
- .mask_memory = parisc_agp_page_mask_memory,
+ .mask_memory = parisc_agp_mask_memory,
.masks = parisc_agp_masks,
.agp_enable = parisc_agp_enable,
.cache_flush = global_cache_flush,
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 73a0765344b6..fe2cb2f5db17 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 9d589e3144de..dde5134713e2 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -30,6 +30,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
+#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/delay.h>
#include <linux/ctype.h>
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 9e4e569dc00d..d400cbd280f2 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -22,6 +22,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/tty.h>
+#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/mm.h>
#include <linux/generic_serial.h>
diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c
index aac0985a572b..31e7c91c2d9d 100644
--- a/drivers/char/genrtc.c
+++ b/drivers/char/genrtc.c
@@ -43,6 +43,7 @@
#define RTC_VERSION "1.07"
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/fcntl.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/istallion.c b/drivers/char/istallion.c
index ab2f3349c5c4..402838f4083e 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -19,6 +19,7 @@
/*****************************************************************************/
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index ec58d8c387ff..d3400b20444f 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -48,6 +48,7 @@
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
+#include <linux/sched.h>
#include <linux/serial.h>
#include <linux/interrupt.h>
#include <linux/kmod.h>
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index e066c4fdf81b..62f282e67638 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -18,6 +18,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/fcntl.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/major.h>
#include <linux/mm.h>
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index 01f2654d5a2e..f121357e5af0 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -32,6 +32,7 @@
*/
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/tty.h>
diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c
index 74339559f0b9..780506326a73 100644
--- a/drivers/char/rio/rioctrl.c
+++ b/drivers/char/rio/rioctrl.c
@@ -31,6 +31,7 @@
*/
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <asm/io.h>
diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c
index 2fb49e89b324..47fab7c33073 100644
--- a/drivers/char/rio/riotty.c
+++ b/drivers/char/rio/riotty.c
@@ -33,6 +33,7 @@
#define __EXPLICIT_DEF_H__
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/tty.h>
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index e0d0f8b2696b..bc4ab3e54550 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -74,6 +74,7 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
+#include <linux/sched.h>
#include <linux/sysctl.h>
#include <linux/wait.h>
#include <linux/bcd.h>
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
index 33a2b531802e..9610861d1f5f 100644
--- a/drivers/char/ser_a2232.c
+++ b/drivers/char/ser_a2232.c
@@ -89,6 +89,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/sched.h>
#include <linux/tty.h>
#include <asm/setup.h>
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index fd3dced97776..8c262aaf7c26 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -36,6 +36,7 @@
*/
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/input.h>
#include <linux/pci.h>
#include <linux/init.h>
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 53e504f41b20..db6dcfa35ba0 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -27,6 +27,7 @@
/*****************************************************************************/
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index 8f2284be68e1..80ea6bcfffdc 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -32,6 +32,7 @@
#include <linux/kernel.h> /* printk() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 45d58002b06c..47c2d2763456 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -696,8 +696,7 @@ int __tpm_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
cmd.header.in = pcrread_header;
cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
- BUG_ON(cmd.header.in.length > READ_PCR_RESULT_SIZE);
- rc = transmit_cmd(chip, &cmd, cmd.header.in.length,
+ rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
"attempting to read a pcr value");
if (rc == 0)
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
index 3108991c5c8b..66fa4e10d76b 100644
--- a/drivers/char/tty_buffer.c
+++ b/drivers/char/tty_buffer.c
@@ -402,28 +402,26 @@ static void flush_to_ldisc(struct work_struct *work)
container_of(work, struct tty_struct, buf.work.work);
unsigned long flags;
struct tty_ldisc *disc;
- struct tty_buffer *tbuf, *head;
- char *char_buf;
- unsigned char *flag_buf;
disc = tty_ldisc_ref(tty);
if (disc == NULL) /* !TTY_LDISC */
return;
spin_lock_irqsave(&tty->buf.lock, flags);
- /* So we know a flush is running */
- set_bit(TTY_FLUSHING, &tty->flags);
- head = tty->buf.head;
- if (head != NULL) {
- tty->buf.head = NULL;
- for (;;) {
- int count = head->commit - head->read;
+
+ if (!test_and_set_bit(TTY_FLUSHING, &tty->flags)) {
+ struct tty_buffer *head;
+ while ((head = tty->buf.head) != NULL) {
+ int count;
+ char *char_buf;
+ unsigned char *flag_buf;
+
+ count = head->commit - head->read;
if (!count) {
if (head->next == NULL)
break;
- tbuf = head;
- head = head->next;
- tty_buffer_free(tty, tbuf);
+ tty->buf.head = head->next;
+ tty_buffer_free(tty, head);
continue;
}
/* Ldisc or user is trying to flush the buffers
@@ -445,9 +443,9 @@ static void flush_to_ldisc(struct work_struct *work)
flag_buf, count);
spin_lock_irqsave(&tty->buf.lock, flags);
}
- /* Restore the queue head */
- tty->buf.head = head;
+ clear_bit(TTY_FLUSHING, &tty->flags);
}
+
/* We may have a deferred request to flush the input buffer,
if so pull the chain under the lock and empty the queue */
if (test_bit(TTY_FLUSHPENDING, &tty->flags)) {
@@ -455,7 +453,6 @@ static void flush_to_ldisc(struct work_struct *work)
clear_bit(TTY_FLUSHPENDING, &tty->flags);
wake_up(&tty->read_wait);
}
- clear_bit(TTY_FLUSHING, &tty->flags);
spin_unlock_irqrestore(&tty->buf.lock, flags);
tty_ldisc_deref(disc);
@@ -471,7 +468,7 @@ static void flush_to_ldisc(struct work_struct *work)
*/
void tty_flush_to_ldisc(struct tty_struct *tty)
{
- flush_to_ldisc(&tty->buf.work.work);
+ flush_delayed_work(&tty->buf.work);
}
/**
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/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index 6b36ee56e6fe..ed86d3bf249a 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -1532,7 +1532,7 @@ long vt_compat_ioctl(struct tty_struct *tty, struct file * file,
case PIO_UNIMAP:
case GIO_UNIMAP:
- ret = do_unimap_ioctl(cmd, up, perm, vc);
+ ret = compat_unimap_ioctl(cmd, up, perm, vc);
break;
/*
diff --git a/drivers/connector/cn_proc.c b/drivers/connector/cn_proc.c
index abf4a2529f80..60697909ebdb 100644
--- a/drivers/connector/cn_proc.c
+++ b/drivers/connector/cn_proc.c
@@ -227,7 +227,8 @@ static void cn_proc_ack(int err, int rcvd_seq, int rcvd_ack)
* cn_proc_mcast_ctl
* @data: message sent from userspace via the connector
*/
-static void cn_proc_mcast_ctl(struct cn_msg *msg)
+static void cn_proc_mcast_ctl(struct cn_msg *msg,
+ struct netlink_skb_parms *nsp)
{
enum proc_cn_mcast_op *mc_op = NULL;
int err = 0;
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/edac/Kconfig b/drivers/edac/Kconfig
index 02127e59fe8e..55c9c59b3f71 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -47,6 +47,18 @@ config EDAC_DEBUG_VERBOSE
Source file name and line number where debugging message
printed will be added to debugging message.
+ config EDAC_DECODE_MCE
+ tristate "Decode MCEs in human-readable form (only on AMD for now)"
+ depends on CPU_SUP_AMD && X86_MCE
+ default y
+ ---help---
+ Enable this option if you want to decode Machine Check Exceptions
+ occuring on your machine in human-readable form.
+
+ You should definitely say Y here in case you want to decode MCEs
+ which occur really early upon boot, before the module infrastructure
+ has been initialized.
+
config EDAC_MM_EDAC
tristate "Main Memory EDAC (Error Detection And Correction) reporting"
help
@@ -59,7 +71,7 @@ config EDAC_MM_EDAC
config EDAC_AMD64
tristate "AMD64 (Opteron, Athlon64) K8, F10h, F11h"
- depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && CPU_SUP_AMD
+ depends on EDAC_MM_EDAC && K8_NB && X86_64 && PCI && EDAC_DECODE_MCE
help
Support for error detection and correction on the AMD 64
Families of Memory Controllers (K8, F10h and F11h)
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 7a473bbe8abd..bc5dc232a0fb 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -6,7 +6,6 @@
# GNU General Public License.
#
-
obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
@@ -17,9 +16,7 @@ ifdef CONFIG_PCI
edac_core-objs += edac_pci.o edac_pci_sysfs.o
endif
-ifdef CONFIG_CPU_SUP_AMD
-edac_core-objs += edac_mce_amd.o
-endif
+obj-$(CONFIG_EDAC_DECODE_MCE) += edac_mce_amd.o
obj-$(CONFIG_EDAC_AMD76X) += amd76x_edac.o
obj-$(CONFIG_EDAC_CPC925) += cpc925_edac.o
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 4e551e63b6dc..4f4ac82382f7 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -15,8 +15,8 @@ module_param(ecc_enable_override, int, 0644);
/* Lookup table for all possible MC control instances */
struct amd64_pvt;
-static struct mem_ctl_info *mci_lookup[MAX_NUMNODES];
-static struct amd64_pvt *pvt_lookup[MAX_NUMNODES];
+static struct mem_ctl_info *mci_lookup[EDAC_MAX_NUMNODES];
+static struct amd64_pvt *pvt_lookup[EDAC_MAX_NUMNODES];
/*
* See F2x80 for K8 and F2x[1,0]80 for Fam10 and later. The table below is only
@@ -189,7 +189,10 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
/* Map from a CSROW entry to the mask entry that operates on it */
static inline u32 amd64_map_to_dcs_mask(struct amd64_pvt *pvt, int csrow)
{
- return csrow >> (pvt->num_dcsm >> 3);
+ if (boot_cpu_data.x86 == 0xf && pvt->ext_model < OPTERON_CPU_REV_F)
+ return csrow;
+ else
+ return csrow >> 1;
}
/* return the 'base' address the i'th CS entry of the 'dct' DRAM controller */
@@ -279,29 +282,26 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
intlv_en = pvt->dram_IntlvEn[0];
if (intlv_en == 0) {
- for (node_id = 0; ; ) {
+ for (node_id = 0; node_id < DRAM_REG_COUNT; node_id++) {
if (amd64_base_limit_match(pvt, sys_addr, node_id))
- break;
-
- if (++node_id >= DRAM_REG_COUNT)
- goto err_no_match;
+ goto found;
}
- goto found;
+ goto err_no_match;
}
- if (unlikely((intlv_en != (0x01 << 8)) &&
- (intlv_en != (0x03 << 8)) &&
- (intlv_en != (0x07 << 8)))) {
+ if (unlikely((intlv_en != 0x01) &&
+ (intlv_en != 0x03) &&
+ (intlv_en != 0x07))) {
amd64_printk(KERN_WARNING, "junk value of 0x%x extracted from "
"IntlvEn field of DRAM Base Register for node 0: "
- "This probably indicates a BIOS bug.\n", intlv_en);
+ "this probably indicates a BIOS bug.\n", intlv_en);
return NULL;
}
bits = (((u32) sys_addr) >> 12) & intlv_en;
for (node_id = 0; ; ) {
- if ((pvt->dram_limit[node_id] & intlv_en) == bits)
+ if ((pvt->dram_IntlvSel[node_id] & intlv_en) == bits)
break; /* intlv_sel field matches */
if (++node_id >= DRAM_REG_COUNT)
@@ -311,10 +311,10 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
/* sanity test for sys_addr */
if (unlikely(!amd64_base_limit_match(pvt, sys_addr, node_id))) {
amd64_printk(KERN_WARNING,
- "%s(): sys_addr 0x%lx falls outside base/limit "
- "address range for node %d with node interleaving "
- "enabled.\n", __func__, (unsigned long)sys_addr,
- node_id);
+ "%s(): sys_addr 0x%llx falls outside base/limit "
+ "address range for node %d with node interleaving "
+ "enabled.\n",
+ __func__, sys_addr, node_id);
return NULL;
}
@@ -377,7 +377,7 @@ static int input_addr_to_csrow(struct mem_ctl_info *mci, u64 input_addr)
* base/mask register pair, test the condition shown near the start of
* section 3.5.4 (p. 84, BKDG #26094, K8, revA-E).
*/
- for (csrow = 0; csrow < CHIPSELECT_COUNT; csrow++) {
+ for (csrow = 0; csrow < pvt->cs_count; csrow++) {
/* This DRAM chip select is disabled on this node */
if ((pvt->dcsb0[csrow] & K8_DCSB_CS_ENABLE) == 0)
@@ -734,7 +734,7 @@ static void find_csrow_limits(struct mem_ctl_info *mci, int csrow,
u64 base, mask;
pvt = mci->pvt_info;
- BUG_ON((csrow < 0) || (csrow >= CHIPSELECT_COUNT));
+ BUG_ON((csrow < 0) || (csrow >= pvt->cs_count));
base = base_from_dct_base(pvt, csrow);
mask = mask_from_dct_mask(pvt, csrow);
@@ -962,35 +962,27 @@ err_reg:
*/
static void amd64_set_dct_base_and_mask(struct amd64_pvt *pvt)
{
- if (pvt->ext_model >= OPTERON_CPU_REV_F) {
+
+ if (boot_cpu_data.x86 == 0xf && pvt->ext_model < OPTERON_CPU_REV_F) {
+ pvt->dcsb_base = REV_E_DCSB_BASE_BITS;
+ pvt->dcsm_mask = REV_E_DCSM_MASK_BITS;
+ pvt->dcs_mask_notused = REV_E_DCS_NOTUSED_BITS;
+ pvt->dcs_shift = REV_E_DCS_SHIFT;
+ pvt->cs_count = 8;
+ pvt->num_dcsm = 8;
+ } else {
pvt->dcsb_base = REV_F_F1Xh_DCSB_BASE_BITS;
pvt->dcsm_mask = REV_F_F1Xh_DCSM_MASK_BITS;
pvt->dcs_mask_notused = REV_F_F1Xh_DCS_NOTUSED_BITS;
pvt->dcs_shift = REV_F_F1Xh_DCS_SHIFT;
- switch (boot_cpu_data.x86) {
- case 0xf:
- pvt->num_dcsm = REV_F_DCSM_COUNT;
- break;
-
- case 0x10:
- pvt->num_dcsm = F10_DCSM_COUNT;
- break;
-
- case 0x11:
- pvt->num_dcsm = F11_DCSM_COUNT;
- break;
-
- default:
- amd64_printk(KERN_ERR, "Unsupported family!\n");
- break;
+ if (boot_cpu_data.x86 == 0x11) {
+ pvt->cs_count = 4;
+ pvt->num_dcsm = 2;
+ } else {
+ pvt->cs_count = 8;
+ pvt->num_dcsm = 4;
}
- } else {
- pvt->dcsb_base = REV_E_DCSB_BASE_BITS;
- pvt->dcsm_mask = REV_E_DCSM_MASK_BITS;
- pvt->dcs_mask_notused = REV_E_DCS_NOTUSED_BITS;
- pvt->dcs_shift = REV_E_DCS_SHIFT;
- pvt->num_dcsm = REV_E_DCSM_COUNT;
}
}
@@ -1003,7 +995,7 @@ static void amd64_read_dct_base_mask(struct amd64_pvt *pvt)
amd64_set_dct_base_and_mask(pvt);
- for (cs = 0; cs < CHIPSELECT_COUNT; cs++) {
+ for (cs = 0; cs < pvt->cs_count; cs++) {
reg = K8_DCSB0 + (cs * 4);
err = pci_read_config_dword(pvt->dram_f2_ctl, reg,
&pvt->dcsb0[cs]);
@@ -1130,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) << 8;
+ pvt->dram_base[dram] = ((u64) low & 0xFFFF0000) << 24;
pvt->dram_IntlvEn[dram] = (low >> 8) & 0x7;
pvt->dram_rw_en[dram] = (low & 0x3);
@@ -1143,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) << 8) | 0x00FFFFFF;
+ pvt->dram_limit[dram] = (((u64) low & 0xFFFF0000) << 24) | 0x00FFFFFF;
pvt->dram_IntlvSel[dram] = (low >> 8) & 0x7;
pvt->dram_DstNode[dram] = (low & 0x7);
}
@@ -1193,7 +1185,7 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
* different from the node that detected the error.
*/
src_mci = find_mc_by_sys_addr(mci, SystemAddress);
- if (src_mci) {
+ if (!src_mci) {
amd64_mc_printk(mci, KERN_ERR,
"failed to map error address 0x%lx to a node\n",
(unsigned long)SystemAddress);
@@ -1376,8 +1368,8 @@ 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) << 32) |
- ((u64) low_base & 0xFFFF0000))) << 8;
+ pvt->dram_base[dram] = (((u64)high_base & 0x000000FF) << 40) |
+ (((u64)low_base & 0xFFFF0000) << 24);
low_offset = K8_DRAM_LIMIT_LOW + (dram << 3);
high_offset = F10_DRAM_LIMIT_HIGH + (dram << 3);
@@ -1398,9 +1390,9 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
* Extract address values and form a LIMIT address. Limit is the HIGHEST
* memory location of the region, so low 24 bits need to be all ones.
*/
- low_limit |= 0x0000FFFF;
- pvt->dram_limit[dram] =
- ((((u64) high_limit << 32) + (u64) low_limit) << 8) | (0xFF);
+ pvt->dram_limit[dram] = (((u64)high_limit & 0x000000FF) << 40) |
+ (((u64) low_limit & 0xFFFF0000) << 24) |
+ 0x00FFFFFF;
}
static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)
@@ -1566,7 +1558,7 @@ static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs)
debugf1("InputAddr=0x%x channelselect=%d\n", in_addr, cs);
- for (csrow = 0; csrow < CHIPSELECT_COUNT; csrow++) {
+ for (csrow = 0; csrow < pvt->cs_count; csrow++) {
cs_base = amd64_get_dct_base(pvt, cs, csrow);
if (!(cs_base & K8_DCSB_CS_ENABLE))
@@ -2497,7 +2489,7 @@ err_reg:
* NOTE: CPU Revision Dependent code
*
* Input:
- * @csrow_nr ChipSelect Row Number (0..CHIPSELECT_COUNT-1)
+ * @csrow_nr ChipSelect Row Number (0..pvt->cs_count-1)
* k8 private pointer to -->
* DRAM Bank Address mapping register
* node_id
@@ -2577,7 +2569,7 @@ static int amd64_init_csrows(struct mem_ctl_info *mci)
(pvt->nbcfg & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled"
);
- for (i = 0; i < CHIPSELECT_COUNT; i++) {
+ for (i = 0; i < pvt->cs_count; i++) {
csrow = &mci->csrows[i];
if ((pvt->dcsb0[i] & K8_DCSB_CS_ENABLE) == 0) {
@@ -2988,7 +2980,7 @@ static int amd64_init_2nd_stage(struct amd64_pvt *pvt)
goto err_exit;
ret = -ENOMEM;
- mci = edac_mc_alloc(0, CHIPSELECT_COUNT, pvt->channel_count, node_id);
+ mci = edac_mc_alloc(0, pvt->cs_count, pvt->channel_count, node_id);
if (!mci)
goto err_exit;
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 8ea07e2715dc..c6f359a85207 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -132,6 +132,8 @@
#define EDAC_AMD64_VERSION " Ver: 3.2.0 " __DATE__
#define EDAC_MOD_STR "amd64_edac"
+#define EDAC_MAX_NUMNODES 8
+
/* Extended Model from CPUID, for CPU Revision numbers */
#define OPTERON_CPU_LE_REV_C 0
#define OPTERON_CPU_REV_D 1
@@ -142,7 +144,7 @@
#define OPTERON_CPU_REV_FA 5
/* Hardware limit on ChipSelect rows per MC and processors per system */
-#define CHIPSELECT_COUNT 8
+#define MAX_CS_COUNT 8
#define DRAM_REG_COUNT 8
@@ -193,7 +195,6 @@
*/
#define REV_E_DCSB_BASE_BITS (0xFFE0FE00ULL)
#define REV_E_DCS_SHIFT 4
-#define REV_E_DCSM_COUNT 8
#define REV_F_F1Xh_DCSB_BASE_BITS (0x1FF83FE0ULL)
#define REV_F_F1Xh_DCS_SHIFT 8
@@ -204,9 +205,6 @@
*/
#define REV_F_DCSB_BASE_BITS (0x1FF83FE0ULL)
#define REV_F_DCS_SHIFT 8
-#define REV_F_DCSM_COUNT 4
-#define F10_DCSM_COUNT 4
-#define F11_DCSM_COUNT 2
/* DRAM CS Mask Registers */
#define K8_DCSM0 0x60
@@ -374,13 +372,11 @@ enum {
#define SET_NB_DRAM_INJECTION_WRITE(word, bits) \
(BIT(((word) & 0xF) + 20) | \
- BIT(17) | \
- ((bits) & 0xF))
+ BIT(17) | bits)
#define SET_NB_DRAM_INJECTION_READ(word, bits) \
(BIT(((word) & 0xF) + 20) | \
- BIT(16) | \
- ((bits) & 0xF))
+ BIT(16) | bits)
#define K8_NBCAP 0xE8
#define K8_NBCAP_CORES (BIT(12)|BIT(13))
@@ -445,12 +441,12 @@ struct amd64_pvt {
u32 dbam1; /* DRAM Base Address Mapping reg for DCT1 */
/* DRAM CS Base Address Registers F2x[1,0][5C:40] */
- u32 dcsb0[CHIPSELECT_COUNT];
- u32 dcsb1[CHIPSELECT_COUNT];
+ u32 dcsb0[MAX_CS_COUNT];
+ u32 dcsb1[MAX_CS_COUNT];
/* DRAM CS Mask Registers F2x[1,0][6C:60] */
- u32 dcsm0[CHIPSELECT_COUNT];
- u32 dcsm1[CHIPSELECT_COUNT];
+ u32 dcsm0[MAX_CS_COUNT];
+ u32 dcsm1[MAX_CS_COUNT];
/*
* Decoded parts of DRAM BASE and LIMIT Registers
@@ -470,6 +466,7 @@ struct amd64_pvt {
*/
u32 dcsb_base; /* DCSB base bits */
u32 dcsm_mask; /* DCSM mask bits */
+ u32 cs_count; /* num chip selects (== num DCSB registers) */
u32 num_dcsm; /* Number of DCSM registers */
u32 dcs_mask_notused; /* DCSM notused mask bits */
u32 dcs_shift; /* DCSB and DCSM shift value */
diff --git a/drivers/edac/amd64_edac_inj.c b/drivers/edac/amd64_edac_inj.c
index d3675b76b3a7..29f1f7a612d9 100644
--- a/drivers/edac/amd64_edac_inj.c
+++ b/drivers/edac/amd64_edac_inj.c
@@ -1,5 +1,11 @@
#include "amd64_edac.h"
+static ssize_t amd64_inject_section_show(struct mem_ctl_info *mci, char *buf)
+{
+ struct amd64_pvt *pvt = mci->pvt_info;
+ return sprintf(buf, "0x%x\n", pvt->injection.section);
+}
+
/*
* store error injection section value which refers to one of 4 16-byte sections
* within a 64-byte cacheline
@@ -15,12 +21,26 @@ static ssize_t amd64_inject_section_store(struct mem_ctl_info *mci,
ret = strict_strtoul(data, 10, &value);
if (ret != -EINVAL) {
+
+ if (value > 3) {
+ amd64_printk(KERN_WARNING,
+ "%s: invalid section 0x%lx\n",
+ __func__, value);
+ return -EINVAL;
+ }
+
pvt->injection.section = (u32) value;
return count;
}
return ret;
}
+static ssize_t amd64_inject_word_show(struct mem_ctl_info *mci, char *buf)
+{
+ struct amd64_pvt *pvt = mci->pvt_info;
+ return sprintf(buf, "0x%x\n", pvt->injection.word);
+}
+
/*
* store error injection word value which refers to one of 9 16-bit word of the
* 16-byte (128-bit + ECC bits) section
@@ -37,14 +57,25 @@ static ssize_t amd64_inject_word_store(struct mem_ctl_info *mci,
ret = strict_strtoul(data, 10, &value);
if (ret != -EINVAL) {
- value = (value <= 8) ? value : 0;
- pvt->injection.word = (u32) value;
+ if (value > 8) {
+ amd64_printk(KERN_WARNING,
+ "%s: invalid word 0x%lx\n",
+ __func__, value);
+ return -EINVAL;
+ }
+ pvt->injection.word = (u32) value;
return count;
}
return ret;
}
+static ssize_t amd64_inject_ecc_vector_show(struct mem_ctl_info *mci, char *buf)
+{
+ struct amd64_pvt *pvt = mci->pvt_info;
+ return sprintf(buf, "0x%x\n", pvt->injection.bit_map);
+}
+
/*
* store 16 bit error injection vector which enables injecting errors to the
* corresponding bit within the error injection word above. When used during a
@@ -60,8 +91,14 @@ static ssize_t amd64_inject_ecc_vector_store(struct mem_ctl_info *mci,
ret = strict_strtoul(data, 16, &value);
if (ret != -EINVAL) {
- pvt->injection.bit_map = (u32) value & 0xFFFF;
+ if (value & 0xFFFF0000) {
+ amd64_printk(KERN_WARNING,
+ "%s: invalid EccVector: 0x%lx\n",
+ __func__, value);
+ return -EINVAL;
+ }
+ pvt->injection.bit_map = (u32) value;
return count;
}
return ret;
@@ -147,7 +184,7 @@ struct mcidev_sysfs_attribute amd64_inj_attrs[] = {
.name = "inject_section",
.mode = (S_IRUGO | S_IWUSR)
},
- .show = NULL,
+ .show = amd64_inject_section_show,
.store = amd64_inject_section_store,
},
{
@@ -155,7 +192,7 @@ struct mcidev_sysfs_attribute amd64_inj_attrs[] = {
.name = "inject_word",
.mode = (S_IRUGO | S_IWUSR)
},
- .show = NULL,
+ .show = amd64_inject_word_show,
.store = amd64_inject_word_store,
},
{
@@ -163,7 +200,7 @@ struct mcidev_sysfs_attribute amd64_inj_attrs[] = {
.name = "inject_ecc_vector",
.mode = (S_IRUGO | S_IWUSR)
},
- .show = NULL,
+ .show = amd64_inject_ecc_vector_show,
.store = amd64_inject_ecc_vector_store,
},
{
diff --git a/drivers/edac/edac_mce_amd.c b/drivers/edac/edac_mce_amd.c
index 0c21c370c9dd..713ed7d37247 100644
--- a/drivers/edac/edac_mce_amd.c
+++ b/drivers/edac/edac_mce_amd.c
@@ -3,6 +3,7 @@
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)
{
@@ -362,7 +363,7 @@ static inline void amd_decode_err_code(unsigned int ec)
pr_warning("Huh? Unknown MCE error 0x%x\n", ec);
}
-void decode_mce(struct mce *m)
+static void amd_decode_mce(struct mce *m)
{
struct err_regs regs;
int node, ecc;
@@ -420,3 +421,32 @@ void decode_mce(struct mce *m)
amd_decode_err_code(m->status & 0xffff);
}
+
+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;
+ }
+
+ return 0;
+}
+early_initcall(mce_amd_init);
+
+#ifdef MODULE
+static void __exit mce_amd_exit(void)
+{
+ x86_mce_decode_callback = orig_mce_callback;
+}
+
+MODULE_DESCRIPTION("AMD MCE decoder");
+MODULE_ALIAS("edac-mce-amd");
+MODULE_LICENSE("GPL");
+module_exit(mce_amd_exit);
+#endif
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 50f0176de615..d485cdd8cbac 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -188,14 +188,7 @@ static struct fw_device *target_device(struct sbp2_target *tgt)
/* Impossible login_id, to detect logout attempt before successful login */
#define INVALID_LOGIN_ID 0x10000
-/*
- * Per section 7.4.8 of the SBP-2 spec, a mgt_ORB_timeout value can be
- * provided in the config rom. Most devices do provide a value, which
- * we'll use for login management orbs, but with some sane limits.
- */
-#define SBP2_MIN_LOGIN_ORB_TIMEOUT 5000U /* Timeout in ms */
-#define SBP2_MAX_LOGIN_ORB_TIMEOUT 40000U /* Timeout in ms */
-#define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */
+#define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */
#define SBP2_ORB_NULL 0x80000000
#define SBP2_RETRY_LIMIT 0xf /* 15 retries */
#define SBP2_CYCLE_LIMIT (0xc8 << 12) /* 200 125us cycles */
@@ -827,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);
}
@@ -1034,7 +1032,6 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
{
struct fw_csr_iterator ci;
int key, value;
- unsigned int timeout;
fw_csr_iterator_init(&ci, directory);
while (fw_csr_iterator_next(&ci, &key, &value)) {
@@ -1059,17 +1056,7 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
case SBP2_CSR_UNIT_CHARACTERISTICS:
/* the timeout value is stored in 500ms units */
- timeout = ((unsigned int) value >> 8 & 0xff) * 500;
- timeout = max(timeout, SBP2_MIN_LOGIN_ORB_TIMEOUT);
- tgt->mgt_orb_timeout =
- min(timeout, SBP2_MAX_LOGIN_ORB_TIMEOUT);
-
- if (timeout > tgt->mgt_orb_timeout)
- fw_notify("%s: config rom contains %ds "
- "management ORB timeout, limiting "
- "to %ds\n", tgt->bus_id,
- timeout / 1000,
- tgt->mgt_orb_timeout / 1000);
+ tgt->mgt_orb_timeout = (value >> 8 & 0xff) * 500;
break;
case SBP2_CSR_LOGICAL_UNIT_NUMBER:
@@ -1087,6 +1074,22 @@ static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
return 0;
}
+/*
+ * Per section 7.4.8 of the SBP-2 spec, a mgt_ORB_timeout value can be
+ * provided in the config rom. Most devices do provide a value, which
+ * we'll use for login management orbs, but with some sane limits.
+ */
+static void sbp2_clamp_management_orb_timeout(struct sbp2_target *tgt)
+{
+ unsigned int timeout = tgt->mgt_orb_timeout;
+
+ if (timeout > 40000)
+ fw_notify("%s: %ds mgt_ORB_timeout limited to 40s\n",
+ tgt->bus_id, timeout / 1000);
+
+ tgt->mgt_orb_timeout = clamp_val(timeout, 5000, 40000);
+}
+
static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
u32 firmware_revision)
{
@@ -1171,6 +1174,7 @@ static int sbp2_probe(struct device *dev)
&firmware_revision) < 0)
goto fail_tgt_put;
+ sbp2_clamp_management_orb_timeout(tgt);
sbp2_init_workarounds(tgt, model, firmware_revision);
/*
diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c
index 420a96e7f2db..051d1ebbd287 100644
--- a/drivers/firmware/iscsi_ibft.c
+++ b/drivers/firmware/iscsi_ibft.c
@@ -939,7 +939,7 @@ static int __init ibft_init(void)
if (ibft_addr) {
printk(KERN_INFO "iBFT detected at 0x%llx.\n",
- (u64)virt_to_phys((void *)ibft_addr));
+ (u64)isa_virt_to_bus(ibft_addr));
rc = ibft_check_device();
if (rc)
diff --git a/drivers/firmware/iscsi_ibft_find.c b/drivers/firmware/iscsi_ibft_find.c
index d53fbbfefa3e..dfb15c06c88f 100644
--- a/drivers/firmware/iscsi_ibft_find.c
+++ b/drivers/firmware/iscsi_ibft_find.c
@@ -65,10 +65,10 @@ void __init reserve_ibft_region(void)
* so skip that area */
if (pos == VGA_MEM)
pos += VGA_SIZE;
- virt = phys_to_virt(pos);
+ virt = isa_bus_to_virt(pos);
if (memcmp(virt, IBFT_SIGN, IBFT_SIGN_LEN) == 0) {
unsigned long *addr =
- (unsigned long *)phys_to_virt(pos + 4);
+ (unsigned long *)isa_bus_to_virt(pos + 4);
len = *addr;
/* if the length of the table extends past 1M,
* the table cannot be valid. */
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_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 8e7b0ebece0c..5cae0b3eee9b 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1556,8 +1556,6 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
struct drm_crtc *crtc;
int ret = 0;
- DRM_DEBUG_KMS("\n");
-
if (!req->flags) {
DRM_ERROR("no operation set\n");
return -EINVAL;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 819ddcbfcce5..23dc9c115fd9 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -454,6 +454,96 @@ out_free:
}
EXPORT_SYMBOL(drm_fb_helper_init_crtc_count);
+static void 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;
+
+ pindex = regno;
+
+ if (fb->bits_per_pixel == 16) {
+ pindex = regno << 3;
+
+ if (fb->depth == 16 && regno > 63)
+ return;
+ if (fb->depth == 15 && regno > 31)
+ return;
+
+ if (fb->depth == 16) {
+ u16 r, g, b;
+ int i;
+ if (regno < 32) {
+ for (i = 0; i < 8; i++)
+ fb_helper->funcs->gamma_set(crtc, red,
+ green, blue, pindex + i);
+ }
+
+ fb_helper->funcs->gamma_get(crtc, &r,
+ &g, &b,
+ pindex >> 1);
+
+ for (i = 0; i < 4; i++)
+ fb_helper->funcs->gamma_set(crtc, r,
+ green, b,
+ (pindex >> 1) + i);
+ }
+ }
+
+ 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);
+ }
+}
+
+int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info)
+{
+ struct drm_fb_helper *fb_helper = info->par;
+ struct drm_device *dev = fb_helper->dev;
+ u16 *red, *green, *blue, *transp;
+ struct drm_crtc *crtc;
+ int i, rc = 0;
+ int start;
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
+ for (i = 0; i < fb_helper->crtc_count; i++) {
+ if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
+ break;
+ }
+ if (i == fb_helper->crtc_count)
+ continue;
+
+ red = cmap->red;
+ green = cmap->green;
+ blue = cmap->blue;
+ transp = cmap->transp;
+ start = cmap->start;
+
+ for (i = 0; i < cmap->len; i++) {
+ u16 hred, hgreen, hblue, htransp = 0xffff;
+
+ hred = *red++;
+ hgreen = *green++;
+ hblue = *blue++;
+
+ if (transp)
+ htransp = *transp++;
+
+ setcolreg(crtc, hred, hgreen, hblue, start++, info);
+ }
+ crtc_funcs->load_lut(crtc);
+ }
+ return rc;
+}
+EXPORT_SYMBOL(drm_fb_helper_setcmap);
+
int drm_fb_helper_setcolreg(unsigned regno,
unsigned red,
unsigned green,
@@ -466,9 +556,11 @@ int drm_fb_helper_setcolreg(unsigned regno,
struct drm_crtc *crtc;
int i;
- list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- struct drm_framebuffer *fb = fb_helper->fb;
+ if (regno > 255)
+ return 1;
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private;
for (i = 0; i < fb_helper->crtc_count; i++) {
if (crtc->base.id == fb_helper->crtc_info[i].crtc_id)
break;
@@ -476,35 +568,9 @@ int drm_fb_helper_setcolreg(unsigned regno,
if (i == fb_helper->crtc_count)
continue;
- if (regno > 255)
- return 1;
-
- if (fb->depth == 8) {
- fb_helper->funcs->gamma_set(crtc, red, green, blue, regno);
- return 0;
- }
- if (regno < 16) {
- switch (fb->depth) {
- case 15:
- fb->pseudo_palette[regno] = ((red & 0xf800) >> 1) |
- ((green & 0xf800) >> 6) |
- ((blue & 0xf800) >> 11);
- break;
- case 16:
- fb->pseudo_palette[regno] = (red & 0xf800) |
- ((green & 0xfc00) >> 5) |
- ((blue & 0xf800) >> 11);
- break;
- case 24:
- case 32:
- fb->pseudo_palette[regno] =
- (((red >> 8) & 0xff) << info->var.red.offset) |
- (((green >> 8) & 0xff) << info->var.green.offset) |
- (((blue >> 8) & 0xff) << info->var.blue.offset);
- break;
- }
- }
+ setcolreg(crtc, red, green, blue, regno, info);
+ crtc_funcs->load_lut(crtc);
}
return 0;
}
@@ -674,6 +740,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
EXPORT_SYMBOL(drm_fb_helper_pan_display);
int drm_fb_helper_single_fb_probe(struct drm_device *dev,
+ int preferred_bpp,
int (*fb_create)(struct drm_device *dev,
uint32_t fb_width,
uint32_t fb_height,
@@ -696,6 +763,11 @@ int drm_fb_helper_single_fb_probe(struct drm_device *dev,
struct drm_fb_helper *fb_helper;
uint32_t surface_depth = 24, surface_bpp = 32;
+ /* if driver picks 8 or 16 by default use that
+ for both depth/bpp */
+ if (preferred_bpp != surface_bpp) {
+ surface_depth = surface_bpp = preferred_bpp;
+ }
/* first up get a count of crtcs now in use and new min/maxes width/heights */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
struct drm_fb_helper_connector *fb_help_conn = connector->fb_helper_private;
@@ -851,10 +923,12 @@ void drm_fb_helper_free(struct drm_fb_helper *helper)
}
EXPORT_SYMBOL(drm_fb_helper_free);
-void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch)
+void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
+ uint32_t depth)
{
info->fix.type = FB_TYPE_PACKED_PIXELS;
- info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.visual = depth == 8 ? FB_VISUAL_PSEUDOCOLOR :
+ FB_VISUAL_DIRECTCOLOR;
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/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 45d507ebd3ff..92aeb918e0c0 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1468,6 +1468,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
spin_lock_init(&dev_priv->user_irq_lock);
spin_lock_init(&dev_priv->error_lock);
dev_priv->user_irq_refcount = 0;
+ dev_priv->trace_irq_seqno = 0;
ret = drm_vblank_init(dev, I915_NUM_PIPE);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index b24b2d145b75..6035d3dae851 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -202,6 +202,7 @@ typedef struct drm_i915_private {
spinlock_t user_irq_lock;
/** Refcount for i915_user_irq_get() versus i915_user_irq_put(). */
int user_irq_refcount;
+ u32 trace_irq_seqno;
/** Cached value of IMR to avoid reads in updating the bitfield */
u32 irq_mask_reg;
u32 pipestat[2];
@@ -665,6 +666,7 @@ extern int i915_irq_emit(struct drm_device *dev, void *data,
extern int i915_irq_wait(struct drm_device *dev, void *data,
struct drm_file *file_priv);
void i915_user_irq_get(struct drm_device *dev);
+void i915_trace_irq_get(struct drm_device *dev, u32 seqno);
void i915_user_irq_put(struct drm_device *dev);
extern void i915_enable_interrupt (struct drm_device *dev);
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 40727d4c2919..abfc27b0c2ea 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -1770,7 +1770,7 @@ i915_gem_retire_requests(struct drm_device *dev)
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t seqno;
- if (!dev_priv->hw_status_page)
+ if (!dev_priv->hw_status_page || list_empty(&dev_priv->mm.request_list))
return;
seqno = i915_get_gem_seqno(dev);
@@ -1794,6 +1794,12 @@ i915_gem_retire_requests(struct drm_device *dev)
} else
break;
}
+
+ if (unlikely (dev_priv->trace_irq_seqno &&
+ i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) {
+ i915_user_irq_put(dev);
+ dev_priv->trace_irq_seqno = 0;
+ }
}
void
@@ -3352,7 +3358,7 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev,
exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
exec_len = (uint32_t) exec->batch_len;
- trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno);
+ trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno + 1);
count = nbox ? nbox : 1;
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index 4dfeec7cdd42..c3ceffa46ea0 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -725,6 +725,16 @@ void i915_user_irq_put(struct drm_device *dev)
spin_unlock_irqrestore(&dev_priv->user_irq_lock, irqflags);
}
+void i915_trace_irq_get(struct drm_device *dev, u32 seqno)
+{
+ drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+
+ if (dev_priv->trace_irq_seqno == 0)
+ i915_user_irq_get(dev);
+
+ dev_priv->trace_irq_seqno = seqno;
+}
+
static int i915_wait_irq(struct drm_device * dev, int irq_nr)
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index 5567a40816f3..01840d9bc38f 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -158,16 +158,17 @@ TRACE_EVENT(i915_gem_request_submit,
TP_ARGS(dev, seqno),
TP_STRUCT__entry(
- __field(struct drm_device *, dev)
+ __field(u32, dev)
__field(u32, seqno)
),
TP_fast_assign(
- __entry->dev = dev;
+ __entry->dev = dev->primary->index;
__entry->seqno = seqno;
+ i915_trace_irq_get(dev, seqno);
),
- TP_printk("dev=%p, seqno=%u", __entry->dev, __entry->seqno)
+ TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno)
);
TRACE_EVENT(i915_gem_request_flush,
@@ -178,20 +179,20 @@ TRACE_EVENT(i915_gem_request_flush,
TP_ARGS(dev, seqno, flush_domains, invalidate_domains),
TP_STRUCT__entry(
- __field(struct drm_device *, dev)
+ __field(u32, dev)
__field(u32, seqno)
__field(u32, flush_domains)
__field(u32, invalidate_domains)
),
TP_fast_assign(
- __entry->dev = dev;
+ __entry->dev = dev->primary->index;
__entry->seqno = seqno;
__entry->flush_domains = flush_domains;
__entry->invalidate_domains = invalidate_domains;
),
- TP_printk("dev=%p, seqno=%u, flush=%04x, invalidate=%04x",
+ TP_printk("dev=%u, seqno=%u, flush=%04x, invalidate=%04x",
__entry->dev, __entry->seqno,
__entry->flush_domains, __entry->invalidate_domains)
);
@@ -204,16 +205,16 @@ TRACE_EVENT(i915_gem_request_complete,
TP_ARGS(dev, seqno),
TP_STRUCT__entry(
- __field(struct drm_device *, dev)
+ __field(u32, dev)
__field(u32, seqno)
),
TP_fast_assign(
- __entry->dev = dev;
+ __entry->dev = dev->primary->index;
__entry->seqno = seqno;
),
- TP_printk("dev=%p, seqno=%u", __entry->dev, __entry->seqno)
+ TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno)
);
TRACE_EVENT(i915_gem_request_retire,
@@ -223,16 +224,16 @@ TRACE_EVENT(i915_gem_request_retire,
TP_ARGS(dev, seqno),
TP_STRUCT__entry(
- __field(struct drm_device *, dev)
+ __field(u32, dev)
__field(u32, seqno)
),
TP_fast_assign(
- __entry->dev = dev;
+ __entry->dev = dev->primary->index;
__entry->seqno = seqno;
),
- TP_printk("dev=%p, seqno=%u", __entry->dev, __entry->seqno)
+ TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno)
);
TRACE_EVENT(i915_gem_request_wait_begin,
@@ -242,16 +243,16 @@ TRACE_EVENT(i915_gem_request_wait_begin,
TP_ARGS(dev, seqno),
TP_STRUCT__entry(
- __field(struct drm_device *, dev)
+ __field(u32, dev)
__field(u32, seqno)
),
TP_fast_assign(
- __entry->dev = dev;
+ __entry->dev = dev->primary->index;
__entry->seqno = seqno;
),
- TP_printk("dev=%p, seqno=%u", __entry->dev, __entry->seqno)
+ TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno)
);
TRACE_EVENT(i915_gem_request_wait_end,
@@ -261,16 +262,16 @@ TRACE_EVENT(i915_gem_request_wait_end,
TP_ARGS(dev, seqno),
TP_STRUCT__entry(
- __field(struct drm_device *, dev)
+ __field(u32, dev)
__field(u32, seqno)
),
TP_fast_assign(
- __entry->dev = dev;
+ __entry->dev = dev->primary->index;
__entry->seqno = seqno;
),
- TP_printk("dev=%p, seqno=%u", __entry->dev, __entry->seqno)
+ TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno)
);
TRACE_EVENT(i915_ring_wait_begin,
@@ -280,14 +281,14 @@ TRACE_EVENT(i915_ring_wait_begin,
TP_ARGS(dev),
TP_STRUCT__entry(
- __field(struct drm_device *, dev)
+ __field(u32, dev)
),
TP_fast_assign(
- __entry->dev = dev;
+ __entry->dev = dev->primary->index;
),
- TP_printk("dev=%p", __entry->dev)
+ TP_printk("dev=%u", __entry->dev)
);
TRACE_EVENT(i915_ring_wait_end,
@@ -297,14 +298,14 @@ TRACE_EVENT(i915_ring_wait_end,
TP_ARGS(dev),
TP_STRUCT__entry(
- __field(struct drm_device *, dev)
+ __field(u32, dev)
),
TP_fast_assign(
- __entry->dev = dev;
+ __entry->dev = dev->primary->index;
),
- TP_printk("dev=%p", __entry->dev)
+ TP_printk("dev=%u", __entry->dev)
);
#endif /* _I915_TRACE_H_ */
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 93ff6c03733e..3c14240cc002 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3095,7 +3095,6 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
struct drm_gem_object *bo;
struct drm_i915_gem_object *obj_priv;
int pipe = intel_crtc->pipe;
- int plane = intel_crtc->plane;
uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR;
uint32_t base = (pipe == 0) ? CURABASE : CURBBASE;
uint32_t temp = I915_READ(control);
@@ -3182,9 +3181,6 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
drm_gem_object_unreference(intel_crtc->cursor_bo);
}
- if ((IS_I965G(dev) || plane == 0))
- intel_update_fbc(crtc, &crtc->mode);
-
mutex_unlock(&dev->struct_mutex);
intel_crtc->cursor_addr = addr;
@@ -3244,6 +3240,16 @@ void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
intel_crtc->lut_b[regno] = blue >> 8;
}
+void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno)
+{
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+ *red = intel_crtc->lut_r[regno] << 8;
+ *green = intel_crtc->lut_g[regno] << 8;
+ *blue = intel_crtc->lut_b[regno] << 8;
+}
+
static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, uint32_t size)
{
@@ -3835,6 +3841,7 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = {
.mode_set_base = intel_pipe_set_base,
.prepare = intel_crtc_prepare,
.commit = intel_crtc_commit,
+ .load_lut = intel_crtc_load_lut,
};
static const struct drm_crtc_funcs intel_crtc_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8aa4b7f30daa..ef61fe9507e2 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -175,6 +175,8 @@ extern int intelfb_resize(struct drm_device *dev, struct drm_crtc *crtc);
extern void intelfb_restore(void);
extern void intel_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno);
+extern void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno);
extern int intel_framebuffer_create(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd,
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index e85d7e9eed7d..2b0fe54cd92c 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -60,10 +60,12 @@ static struct fb_ops intelfb_ops = {
.fb_imageblit = cfb_imageblit,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
+ .fb_setcmap = drm_fb_helper_setcmap,
};
static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
.gamma_set = intel_crtc_fb_gamma_set,
+ .gamma_get = intel_crtc_fb_gamma_get,
};
@@ -123,6 +125,10 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
struct device *device = &dev->pdev->dev;
int size, ret, mmio_bar = IS_I9XX(dev) ? 0 : 1;
+ /* we don't do packed 24bpp */
+ if (surface_bpp == 24)
+ surface_bpp = 32;
+
mode_cmd.width = surface_width;
mode_cmd.height = surface_height;
@@ -206,7 +212,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
// memset(info->screen_base, 0, size);
- drm_fb_helper_fill_fix(info, fb->pitch);
+ drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
drm_fb_helper_fill_var(info, fb, fb_width, fb_height);
/* FIXME: we really shouldn't expose mmio space at all */
@@ -244,7 +250,7 @@ int intelfb_probe(struct drm_device *dev)
int ret;
DRM_DEBUG("\n");
- ret = drm_fb_helper_single_fb_probe(dev, intelfb_create);
+ ret = drm_fb_helper_single_fb_probe(dev, 32, intelfb_create);
return ret;
}
EXPORT_SYMBOL(intelfb_probe);
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index fa304e136010..663ab6de0b58 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -223,7 +223,7 @@ void intel_hdmi_init(struct drm_device *dev, int sdvox_reg)
connector = &intel_output->base;
drm_connector_init(dev, connector, &intel_hdmi_connector_funcs,
- DRM_MODE_CONNECTOR_DVID);
+ DRM_MODE_CONNECTOR_HDMIA);
drm_connector_helper_add(connector, &intel_hdmi_connector_helper_funcs);
intel_output->type = INTEL_OUTPUT_HDMI;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index c64eab493fb0..9ca917931afb 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -1082,7 +1082,8 @@ intel_tv_mode_valid(struct drm_connector *connector, struct drm_display_mode *mo
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_output);
/* Ensure TV refresh is close to desired refresh */
- if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode)) < 10)
+ if (tv_mode && abs(tv_mode->refresh - drm_mode_vrefresh(mode) * 1000)
+ < 1000)
return MODE_OK;
return MODE_CLOCK_RANGE;
}
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index 6a015929deee..3409aa3cbee4 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -248,18 +248,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 +270,89 @@ 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);
}
void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode *mode)
@@ -333,12 +363,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;
@@ -393,14 +424,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 +463,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 +476,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 +491,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;
@@ -563,6 +617,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 +632,22 @@ 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_crtc_set_pll(crtc, adjusted_mode);
- atombios_crtc_set_timing(crtc, &crtc_timing);
+ 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;
}
@@ -733,6 +679,7 @@ static const struct drm_crtc_helper_funcs atombios_helper_funcs = {
.mode_set_base = atombios_crtc_set_base,
.prepare = atombios_crtc_prepare,
.commit = atombios_crtc_commit,
+ .load_lut = radeon_crtc_load_lut,
};
void radeon_atombios_init_crtc(struct drm_device *dev,
diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index e6cce24de802..1fcea2da69e6 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -32,6 +32,9 @@
#include "radeon_reg.h"
#include "radeon.h"
#include "r100d.h"
+#include "rs100d.h"
+#include "rv200d.h"
+#include "rv250d.h"
#include <linux/firmware.h>
#include <linux/platform_device.h>
@@ -60,18 +63,7 @@ MODULE_FIRMWARE(FIRMWARE_R520);
/* This files gather functions specifics to:
* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
- *
- * Some of these functions might be used by newer ASICs.
*/
-int r200_init(struct radeon_device *rdev);
-void r100_hdp_reset(struct radeon_device *rdev);
-void r100_gpu_init(struct radeon_device *rdev);
-int r100_gui_wait_for_idle(struct radeon_device *rdev);
-int r100_mc_wait_for_idle(struct radeon_device *rdev);
-void r100_gpu_wait_for_vsync(struct radeon_device *rdev);
-void r100_gpu_wait_for_vsync2(struct radeon_device *rdev);
-int r100_debugfs_mc_info_init(struct radeon_device *rdev);
-
/*
* PCI GART
@@ -152,136 +144,6 @@ void r100_pci_gart_fini(struct radeon_device *rdev)
radeon_gart_fini(rdev);
}
-
-/*
- * MC
- */
-void r100_mc_disable_clients(struct radeon_device *rdev)
-{
- uint32_t ov0_scale_cntl, crtc_ext_cntl, crtc_gen_cntl, crtc2_gen_cntl;
-
- /* FIXME: is this function correct for rs100,rs200,rs300 ? */
- if (r100_gui_wait_for_idle(rdev)) {
- printk(KERN_WARNING "Failed to wait GUI idle while "
- "programming pipes. Bad things might happen.\n");
- }
-
- /* stop display and memory access */
- ov0_scale_cntl = RREG32(RADEON_OV0_SCALE_CNTL);
- WREG32(RADEON_OV0_SCALE_CNTL, ov0_scale_cntl & ~RADEON_SCALER_ENABLE);
- crtc_ext_cntl = RREG32(RADEON_CRTC_EXT_CNTL);
- WREG32(RADEON_CRTC_EXT_CNTL, crtc_ext_cntl | RADEON_CRTC_DISPLAY_DIS);
- crtc_gen_cntl = RREG32(RADEON_CRTC_GEN_CNTL);
-
- r100_gpu_wait_for_vsync(rdev);
-
- WREG32(RADEON_CRTC_GEN_CNTL,
- (crtc_gen_cntl & ~(RADEON_CRTC_CUR_EN | RADEON_CRTC_ICON_EN)) |
- RADEON_CRTC_DISP_REQ_EN_B | RADEON_CRTC_EXT_DISP_EN);
-
- if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
- crtc2_gen_cntl = RREG32(RADEON_CRTC2_GEN_CNTL);
-
- r100_gpu_wait_for_vsync2(rdev);
- WREG32(RADEON_CRTC2_GEN_CNTL,
- (crtc2_gen_cntl &
- ~(RADEON_CRTC2_CUR_EN | RADEON_CRTC2_ICON_EN)) |
- RADEON_CRTC2_DISP_REQ_EN_B);
- }
-
- udelay(500);
-}
-
-void r100_mc_setup(struct radeon_device *rdev)
-{
- uint32_t tmp;
- int r;
-
- r = r100_debugfs_mc_info_init(rdev);
- if (r) {
- DRM_ERROR("Failed to register debugfs file for R100 MC !\n");
- }
- /* Write VRAM size in case we are limiting it */
- WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.real_vram_size);
- /* Novell bug 204882 for RN50/M6/M7 with 8/16/32MB VRAM,
- * if the aperture is 64MB but we have 32MB VRAM
- * we report only 32MB VRAM but we have to set MC_FB_LOCATION
- * to 64MB, otherwise the gpu accidentially dies */
- tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
- tmp = REG_SET(RADEON_MC_FB_TOP, tmp >> 16);
- tmp |= REG_SET(RADEON_MC_FB_START, rdev->mc.vram_location >> 16);
- WREG32(RADEON_MC_FB_LOCATION, tmp);
-
- /* Enable bus mastering */
- tmp = RREG32(RADEON_BUS_CNTL) & ~RADEON_BUS_MASTER_DIS;
- WREG32(RADEON_BUS_CNTL, tmp);
-
- if (rdev->flags & RADEON_IS_AGP) {
- tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
- tmp = REG_SET(RADEON_MC_AGP_TOP, tmp >> 16);
- tmp |= REG_SET(RADEON_MC_AGP_START, rdev->mc.gtt_location >> 16);
- WREG32(RADEON_MC_AGP_LOCATION, tmp);
- WREG32(RADEON_AGP_BASE, rdev->mc.agp_base);
- } else {
- WREG32(RADEON_MC_AGP_LOCATION, 0x0FFFFFFF);
- WREG32(RADEON_AGP_BASE, 0);
- }
-
- tmp = RREG32(RADEON_HOST_PATH_CNTL) & RADEON_HDP_APER_CNTL;
- tmp |= (7 << 28);
- WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE);
- (void)RREG32(RADEON_HOST_PATH_CNTL);
- WREG32(RADEON_HOST_PATH_CNTL, tmp);
- (void)RREG32(RADEON_HOST_PATH_CNTL);
-}
-
-int r100_mc_init(struct radeon_device *rdev)
-{
- int r;
-
- if (r100_debugfs_rbbm_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for RBBM !\n");
- }
-
- r100_gpu_init(rdev);
- /* Disable gart which also disable out of gart access */
- r100_pci_gart_disable(rdev);
-
- /* Setup GPU memory space */
- rdev->mc.gtt_location = 0xFFFFFFFFUL;
- if (rdev->flags & RADEON_IS_AGP) {
- r = radeon_agp_init(rdev);
- if (r) {
- printk(KERN_WARNING "[drm] Disabling AGP\n");
- rdev->flags &= ~RADEON_IS_AGP;
- rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
- } else {
- rdev->mc.gtt_location = rdev->mc.agp_base;
- }
- }
- r = radeon_mc_setup(rdev);
- if (r) {
- return r;
- }
-
- r100_mc_disable_clients(rdev);
- if (r100_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "Failed to wait MC idle while "
- "programming pipes. Bad things might happen.\n");
- }
-
- r100_mc_setup(rdev);
- return 0;
-}
-
-void r100_mc_fini(struct radeon_device *rdev)
-{
-}
-
-
-/*
- * Interrupts
- */
int r100_irq_set(struct radeon_device *rdev)
{
uint32_t tmp = 0;
@@ -358,10 +220,6 @@ u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc)
return RREG32(RADEON_CRTC2_CRNT_FRAME);
}
-
-/*
- * Fence emission
- */
void r100_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence)
{
@@ -377,10 +235,6 @@ void r100_fence_ring_emit(struct radeon_device *rdev,
radeon_ring_write(rdev, RADEON_SW_INT_FIRE);
}
-
-/*
- * Writeback
- */
int r100_wb_init(struct radeon_device *rdev)
{
int r;
@@ -504,10 +358,6 @@ int r100_copy_blit(struct radeon_device *rdev,
return r;
}
-
-/*
- * CP
- */
static int r100_cp_wait_for_idle(struct radeon_device *rdev)
{
unsigned i;
@@ -612,6 +462,7 @@ static int r100_cp_init_microcode(struct radeon_device *rdev)
}
return err;
}
+
static void r100_cp_load_microcode(struct radeon_device *rdev)
{
const __be32 *fw_data;
@@ -978,7 +829,7 @@ int r100_cs_packet_parse_vline(struct radeon_cs_parser *p)
header = radeon_get_ib_value(p, h_idx);
crtc_id = radeon_get_ib_value(p, h_idx + 5);
- reg = header >> 2;
+ reg = CP_PACKET0_GET_REG(header);
mutex_lock(&p->rdev->ddev->mode_config.mutex);
obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);
if (!obj) {
@@ -1990,7 +1841,7 @@ void r100_pll_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
r100_pll_errata_after_data(rdev);
}
-int r100_init(struct radeon_device *rdev)
+void r100_set_safe_registers(struct radeon_device *rdev)
{
if (ASIC_IS_RN50(rdev)) {
rdev->config.r100.reg_safe_bm = rn50_reg_safe_bm;
@@ -1999,9 +1850,8 @@ int r100_init(struct radeon_device *rdev)
rdev->config.r100.reg_safe_bm = r100_reg_safe_bm;
rdev->config.r100.reg_safe_bm_size = ARRAY_SIZE(r100_reg_safe_bm);
} else {
- return r200_init(rdev);
+ r200_set_safe_registers(rdev);
}
- return 0;
}
/*
@@ -2299,9 +2149,11 @@ void r100_bandwidth_update(struct radeon_device *rdev)
mode1 = &rdev->mode_info.crtcs[0]->base.mode;
pixel_bytes1 = rdev->mode_info.crtcs[0]->base.fb->bits_per_pixel / 8;
}
- if (rdev->mode_info.crtcs[1]->base.enabled) {
- mode2 = &rdev->mode_info.crtcs[1]->base.mode;
- pixel_bytes2 = rdev->mode_info.crtcs[1]->base.fb->bits_per_pixel / 8;
+ if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
+ if (rdev->mode_info.crtcs[1]->base.enabled) {
+ mode2 = &rdev->mode_info.crtcs[1]->base.mode;
+ pixel_bytes2 = rdev->mode_info.crtcs[1]->base.fb->bits_per_pixel / 8;
+ }
}
min_mem_eff.full = rfixed_const_8(0);
@@ -2512,7 +2364,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;
@@ -3114,7 +2966,7 @@ void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save)
WREG32(R_000740_CP_CSQ_CNTL, 0);
/* Save few CRTC registers */
- save->GENMO_WT = RREG32(R_0003C0_GENMO_WT);
+ save->GENMO_WT = RREG8(R_0003C2_GENMO_WT);
save->CRTC_EXT_CNTL = RREG32(R_000054_CRTC_EXT_CNTL);
save->CRTC_GEN_CNTL = RREG32(R_000050_CRTC_GEN_CNTL);
save->CUR_OFFSET = RREG32(R_000260_CUR_OFFSET);
@@ -3124,7 +2976,7 @@ void r100_mc_stop(struct radeon_device *rdev, struct r100_mc_save *save)
}
/* Disable VGA aperture access */
- WREG32(R_0003C0_GENMO_WT, C_0003C0_VGA_RAM_EN & save->GENMO_WT);
+ WREG8(R_0003C2_GENMO_WT, C_0003C2_VGA_RAM_EN & save->GENMO_WT);
/* Disable cursor, overlay, crtc */
WREG32(R_000260_CUR_OFFSET, save->CUR_OFFSET | S_000260_CUR_LOCK(1));
WREG32(R_000054_CRTC_EXT_CNTL, save->CRTC_EXT_CNTL |
@@ -3156,10 +3008,264 @@ void r100_mc_resume(struct radeon_device *rdev, struct r100_mc_save *save)
rdev->mc.vram_location);
}
/* Restore CRTC registers */
- WREG32(R_0003C0_GENMO_WT, save->GENMO_WT);
+ WREG8(R_0003C2_GENMO_WT, save->GENMO_WT);
WREG32(R_000054_CRTC_EXT_CNTL, save->CRTC_EXT_CNTL);
WREG32(R_000050_CRTC_GEN_CNTL, save->CRTC_GEN_CNTL);
if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
WREG32(R_0003F8_CRTC2_GEN_CNTL, save->CRTC2_GEN_CNTL);
}
}
+
+void r100_vga_render_disable(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ tmp = RREG8(R_0003C2_GENMO_WT);
+ WREG8(R_0003C2_GENMO_WT, C_0003C2_VGA_RAM_EN & tmp);
+}
+
+static void r100_debugfs(struct radeon_device *rdev)
+{
+ int r;
+
+ r = r100_debugfs_mc_info_init(rdev);
+ if (r)
+ dev_warn(rdev->dev, "Failed to create r100_mc debugfs file.\n");
+}
+
+static void r100_mc_program(struct radeon_device *rdev)
+{
+ struct r100_mc_save save;
+
+ /* Stops all mc clients */
+ r100_mc_stop(rdev, &save);
+ if (rdev->flags & RADEON_IS_AGP) {
+ WREG32(R_00014C_MC_AGP_LOCATION,
+ S_00014C_MC_AGP_START(rdev->mc.gtt_start >> 16) |
+ S_00014C_MC_AGP_TOP(rdev->mc.gtt_end >> 16));
+ WREG32(R_000170_AGP_BASE, lower_32_bits(rdev->mc.agp_base));
+ if (rdev->family > CHIP_RV200)
+ WREG32(R_00015C_AGP_BASE_2,
+ upper_32_bits(rdev->mc.agp_base) & 0xff);
+ } else {
+ WREG32(R_00014C_MC_AGP_LOCATION, 0x0FFFFFFF);
+ WREG32(R_000170_AGP_BASE, 0);
+ if (rdev->family > CHIP_RV200)
+ WREG32(R_00015C_AGP_BASE_2, 0);
+ }
+ /* Wait for mc idle */
+ if (r100_mc_wait_for_idle(rdev))
+ dev_warn(rdev->dev, "Wait for MC idle timeout.\n");
+ /* Program MC, should be a 32bits limited address space */
+ WREG32(R_000148_MC_FB_LOCATION,
+ S_000148_MC_FB_START(rdev->mc.vram_start >> 16) |
+ S_000148_MC_FB_TOP(rdev->mc.vram_end >> 16));
+ r100_mc_resume(rdev, &save);
+}
+
+void r100_clock_startup(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ if (radeon_dynclks != -1 && radeon_dynclks)
+ radeon_legacy_set_clock_gating(rdev, 1);
+ /* We need to force on some of the block */
+ tmp = RREG32_PLL(R_00000D_SCLK_CNTL);
+ tmp |= S_00000D_FORCE_CP(1) | S_00000D_FORCE_VIP(1);
+ if ((rdev->family == CHIP_RV250) || (rdev->family == CHIP_RV280))
+ tmp |= S_00000D_FORCE_DISP1(1) | S_00000D_FORCE_DISP2(1);
+ WREG32_PLL(R_00000D_SCLK_CNTL, tmp);
+}
+
+static int r100_startup(struct radeon_device *rdev)
+{
+ int r;
+
+ r100_mc_program(rdev);
+ /* Resume clock */
+ r100_clock_startup(rdev);
+ /* Initialize GPU configuration (# pipes, ...) */
+ r100_gpu_init(rdev);
+ /* Initialize GART (initialize after TTM so we can allocate
+ * memory through TTM but finalize after TTM) */
+ if (rdev->flags & RADEON_IS_PCI) {
+ r = r100_pci_gart_enable(rdev);
+ if (r)
+ return r;
+ }
+ /* Enable IRQ */
+ rdev->irq.sw_int = true;
+ r100_irq_set(rdev);
+ /* 1M ring buffer */
+ r = r100_cp_init(rdev, 1024 * 1024);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ return r;
+ }
+ r = r100_wb_init(rdev);
+ if (r)
+ dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
+ r = r100_ib_init(rdev);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ return r;
+ }
+ return 0;
+}
+
+int r100_resume(struct radeon_device *rdev)
+{
+ /* Make sur GART are not working */
+ if (rdev->flags & RADEON_IS_PCI)
+ r100_pci_gart_disable(rdev);
+ /* Resume clock before doing reset */
+ r100_clock_startup(rdev);
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_reset(rdev)) {
+ dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
+ RREG32(R_000E40_RBBM_STATUS),
+ RREG32(R_0007C0_CP_STAT));
+ }
+ /* post */
+ radeon_combios_asic_init(rdev->ddev);
+ /* Resume clock after posting */
+ r100_clock_startup(rdev);
+ return r100_startup(rdev);
+}
+
+int r100_suspend(struct radeon_device *rdev)
+{
+ r100_cp_disable(rdev);
+ r100_wb_disable(rdev);
+ r100_irq_disable(rdev);
+ if (rdev->flags & RADEON_IS_PCI)
+ r100_pci_gart_disable(rdev);
+ return 0;
+}
+
+void r100_fini(struct radeon_device *rdev)
+{
+ r100_suspend(rdev);
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ radeon_gem_fini(rdev);
+ if (rdev->flags & RADEON_IS_PCI)
+ r100_pci_gart_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ radeon_fence_driver_fini(rdev);
+ radeon_object_fini(rdev);
+ radeon_atombios_fini(rdev);
+ kfree(rdev->bios);
+ rdev->bios = NULL;
+}
+
+int r100_mc_init(struct radeon_device *rdev)
+{
+ int r;
+ u32 tmp;
+
+ /* Setup GPU memory space */
+ rdev->mc.vram_location = 0xFFFFFFFFUL;
+ rdev->mc.gtt_location = 0xFFFFFFFFUL;
+ if (rdev->flags & RADEON_IS_IGP) {
+ tmp = G_00015C_MC_FB_START(RREG32(R_00015C_NB_TOM));
+ rdev->mc.vram_location = tmp << 16;
+ }
+ if (rdev->flags & RADEON_IS_AGP) {
+ r = radeon_agp_init(rdev);
+ if (r) {
+ printk(KERN_WARNING "[drm] Disabling AGP\n");
+ rdev->flags &= ~RADEON_IS_AGP;
+ rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
+ } else {
+ rdev->mc.gtt_location = rdev->mc.agp_base;
+ }
+ }
+ r = radeon_mc_setup(rdev);
+ if (r)
+ return r;
+ return 0;
+}
+
+int r100_init(struct radeon_device *rdev)
+{
+ int r;
+
+ /* Register debugfs file specific to this group of asics */
+ r100_debugfs(rdev);
+ /* Disable VGA */
+ r100_vga_render_disable(rdev);
+ /* Initialize scratch registers */
+ radeon_scratch_init(rdev);
+ /* Initialize surface registers */
+ radeon_surface_init(rdev);
+ /* TODO: disable VGA need to use VGA request */
+ /* BIOS*/
+ if (!radeon_get_bios(rdev)) {
+ if (ASIC_IS_AVIVO(rdev))
+ return -EINVAL;
+ }
+ if (rdev->is_atom_bios) {
+ dev_err(rdev->dev, "Expecting combios for RS400/RS480 GPU\n");
+ return -EINVAL;
+ } else {
+ r = radeon_combios_init(rdev);
+ if (r)
+ return r;
+ }
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_reset(rdev)) {
+ dev_warn(rdev->dev,
+ "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
+ RREG32(R_000E40_RBBM_STATUS),
+ RREG32(R_0007C0_CP_STAT));
+ }
+ /* check if cards are posted or not */
+ if (!radeon_card_posted(rdev) && rdev->bios) {
+ DRM_INFO("GPU not posted. posting now...\n");
+ radeon_combios_asic_init(rdev->ddev);
+ }
+ /* Set asic errata */
+ r100_errata(rdev);
+ /* Initialize clocks */
+ radeon_get_clock_info(rdev->ddev);
+ /* Get vram informations */
+ r100_vram_info(rdev);
+ /* Initialize memory controller (also test AGP) */
+ r = r100_mc_init(rdev);
+ if (r)
+ return r;
+ /* Fence driver */
+ r = radeon_fence_driver_init(rdev);
+ if (r)
+ return r;
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ /* Memory manager */
+ r = radeon_object_init(rdev);
+ if (r)
+ return r;
+ if (rdev->flags & RADEON_IS_PCI) {
+ r = r100_pci_gart_init(rdev);
+ if (r)
+ return r;
+ }
+ r100_set_safe_registers(rdev);
+ rdev->accel_working = true;
+ r = r100_startup(rdev);
+ if (r) {
+ /* Somethings want wront with the accel init stop accel */
+ dev_err(rdev->dev, "Disabling GPU acceleration\n");
+ r100_suspend(rdev);
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ if (rdev->flags & RADEON_IS_PCI)
+ r100_pci_gart_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ rdev->accel_working = false;
+ }
+ return 0;
+}
diff --git a/drivers/gpu/drm/radeon/r100d.h b/drivers/gpu/drm/radeon/r100d.h
index c4b257ec920e..df29a630c466 100644
--- a/drivers/gpu/drm/radeon/r100d.h
+++ b/drivers/gpu/drm/radeon/r100d.h
@@ -381,6 +381,24 @@
#define S_000054_VCRTC_IDX_MASTER(x) (((x) & 0x7F) << 24)
#define G_000054_VCRTC_IDX_MASTER(x) (((x) >> 24) & 0x7F)
#define C_000054_VCRTC_IDX_MASTER 0x80FFFFFF
+#define R_000148_MC_FB_LOCATION 0x000148
+#define S_000148_MC_FB_START(x) (((x) & 0xFFFF) << 0)
+#define G_000148_MC_FB_START(x) (((x) >> 0) & 0xFFFF)
+#define C_000148_MC_FB_START 0xFFFF0000
+#define S_000148_MC_FB_TOP(x) (((x) & 0xFFFF) << 16)
+#define G_000148_MC_FB_TOP(x) (((x) >> 16) & 0xFFFF)
+#define C_000148_MC_FB_TOP 0x0000FFFF
+#define R_00014C_MC_AGP_LOCATION 0x00014C
+#define S_00014C_MC_AGP_START(x) (((x) & 0xFFFF) << 0)
+#define G_00014C_MC_AGP_START(x) (((x) >> 0) & 0xFFFF)
+#define C_00014C_MC_AGP_START 0xFFFF0000
+#define S_00014C_MC_AGP_TOP(x) (((x) & 0xFFFF) << 16)
+#define G_00014C_MC_AGP_TOP(x) (((x) >> 16) & 0xFFFF)
+#define C_00014C_MC_AGP_TOP 0x0000FFFF
+#define R_000170_AGP_BASE 0x000170
+#define S_000170_AGP_BASE_ADDR(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_000170_AGP_BASE_ADDR(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_000170_AGP_BASE_ADDR 0x00000000
#define R_00023C_DISPLAY_BASE_ADDR 0x00023C
#define S_00023C_DISPLAY_BASE_ADDR(x) (((x) & 0xFFFFFFFF) << 0)
#define G_00023C_DISPLAY_BASE_ADDR(x) (((x) >> 0) & 0xFFFFFFFF)
@@ -403,25 +421,25 @@
#define S_000360_CUR2_LOCK(x) (((x) & 0x1) << 31)
#define G_000360_CUR2_LOCK(x) (((x) >> 31) & 0x1)
#define C_000360_CUR2_LOCK 0x7FFFFFFF
-#define R_0003C0_GENMO_WT 0x0003C0
-#define S_0003C0_GENMO_MONO_ADDRESS_B(x) (((x) & 0x1) << 0)
-#define G_0003C0_GENMO_MONO_ADDRESS_B(x) (((x) >> 0) & 0x1)
-#define C_0003C0_GENMO_MONO_ADDRESS_B 0xFFFFFFFE
-#define S_0003C0_VGA_RAM_EN(x) (((x) & 0x1) << 1)
-#define G_0003C0_VGA_RAM_EN(x) (((x) >> 1) & 0x1)
-#define C_0003C0_VGA_RAM_EN 0xFFFFFFFD
-#define S_0003C0_VGA_CKSEL(x) (((x) & 0x3) << 2)
-#define G_0003C0_VGA_CKSEL(x) (((x) >> 2) & 0x3)
-#define C_0003C0_VGA_CKSEL 0xFFFFFFF3
-#define S_0003C0_ODD_EVEN_MD_PGSEL(x) (((x) & 0x1) << 5)
-#define G_0003C0_ODD_EVEN_MD_PGSEL(x) (((x) >> 5) & 0x1)
-#define C_0003C0_ODD_EVEN_MD_PGSEL 0xFFFFFFDF
-#define S_0003C0_VGA_HSYNC_POL(x) (((x) & 0x1) << 6)
-#define G_0003C0_VGA_HSYNC_POL(x) (((x) >> 6) & 0x1)
-#define C_0003C0_VGA_HSYNC_POL 0xFFFFFFBF
-#define S_0003C0_VGA_VSYNC_POL(x) (((x) & 0x1) << 7)
-#define G_0003C0_VGA_VSYNC_POL(x) (((x) >> 7) & 0x1)
-#define C_0003C0_VGA_VSYNC_POL 0xFFFFFF7F
+#define R_0003C2_GENMO_WT 0x0003C0
+#define S_0003C2_GENMO_MONO_ADDRESS_B(x) (((x) & 0x1) << 0)
+#define G_0003C2_GENMO_MONO_ADDRESS_B(x) (((x) >> 0) & 0x1)
+#define C_0003C2_GENMO_MONO_ADDRESS_B 0xFE
+#define S_0003C2_VGA_RAM_EN(x) (((x) & 0x1) << 1)
+#define G_0003C2_VGA_RAM_EN(x) (((x) >> 1) & 0x1)
+#define C_0003C2_VGA_RAM_EN 0xFD
+#define S_0003C2_VGA_CKSEL(x) (((x) & 0x3) << 2)
+#define G_0003C2_VGA_CKSEL(x) (((x) >> 2) & 0x3)
+#define C_0003C2_VGA_CKSEL 0xF3
+#define S_0003C2_ODD_EVEN_MD_PGSEL(x) (((x) & 0x1) << 5)
+#define G_0003C2_ODD_EVEN_MD_PGSEL(x) (((x) >> 5) & 0x1)
+#define C_0003C2_ODD_EVEN_MD_PGSEL 0xDF
+#define S_0003C2_VGA_HSYNC_POL(x) (((x) & 0x1) << 6)
+#define G_0003C2_VGA_HSYNC_POL(x) (((x) >> 6) & 0x1)
+#define C_0003C2_VGA_HSYNC_POL 0xBF
+#define S_0003C2_VGA_VSYNC_POL(x) (((x) & 0x1) << 7)
+#define G_0003C2_VGA_VSYNC_POL(x) (((x) >> 7) & 0x1)
+#define C_0003C2_VGA_VSYNC_POL 0x7F
#define R_0003F8_CRTC2_GEN_CNTL 0x0003F8
#define S_0003F8_CRTC2_DBL_SCAN_EN(x) (((x) & 0x1) << 0)
#define G_0003F8_CRTC2_DBL_SCAN_EN(x) (((x) >> 0) & 0x1)
@@ -545,6 +563,46 @@
#define S_000774_SCRATCH_ADDR(x) (((x) & 0x7FFFFFF) << 5)
#define G_000774_SCRATCH_ADDR(x) (((x) >> 5) & 0x7FFFFFF)
#define C_000774_SCRATCH_ADDR 0x0000001F
+#define R_0007C0_CP_STAT 0x0007C0
+#define S_0007C0_MRU_BUSY(x) (((x) & 0x1) << 0)
+#define G_0007C0_MRU_BUSY(x) (((x) >> 0) & 0x1)
+#define C_0007C0_MRU_BUSY 0xFFFFFFFE
+#define S_0007C0_MWU_BUSY(x) (((x) & 0x1) << 1)
+#define G_0007C0_MWU_BUSY(x) (((x) >> 1) & 0x1)
+#define C_0007C0_MWU_BUSY 0xFFFFFFFD
+#define S_0007C0_RSIU_BUSY(x) (((x) & 0x1) << 2)
+#define G_0007C0_RSIU_BUSY(x) (((x) >> 2) & 0x1)
+#define C_0007C0_RSIU_BUSY 0xFFFFFFFB
+#define S_0007C0_RCIU_BUSY(x) (((x) & 0x1) << 3)
+#define G_0007C0_RCIU_BUSY(x) (((x) >> 3) & 0x1)
+#define C_0007C0_RCIU_BUSY 0xFFFFFFF7
+#define S_0007C0_CSF_PRIMARY_BUSY(x) (((x) & 0x1) << 9)
+#define G_0007C0_CSF_PRIMARY_BUSY(x) (((x) >> 9) & 0x1)
+#define C_0007C0_CSF_PRIMARY_BUSY 0xFFFFFDFF
+#define S_0007C0_CSF_INDIRECT_BUSY(x) (((x) & 0x1) << 10)
+#define G_0007C0_CSF_INDIRECT_BUSY(x) (((x) >> 10) & 0x1)
+#define C_0007C0_CSF_INDIRECT_BUSY 0xFFFFFBFF
+#define S_0007C0_CSQ_PRIMARY_BUSY(x) (((x) & 0x1) << 11)
+#define G_0007C0_CSQ_PRIMARY_BUSY(x) (((x) >> 11) & 0x1)
+#define C_0007C0_CSQ_PRIMARY_BUSY 0xFFFFF7FF
+#define S_0007C0_CSQ_INDIRECT_BUSY(x) (((x) & 0x1) << 12)
+#define G_0007C0_CSQ_INDIRECT_BUSY(x) (((x) >> 12) & 0x1)
+#define C_0007C0_CSQ_INDIRECT_BUSY 0xFFFFEFFF
+#define S_0007C0_CSI_BUSY(x) (((x) & 0x1) << 13)
+#define G_0007C0_CSI_BUSY(x) (((x) >> 13) & 0x1)
+#define C_0007C0_CSI_BUSY 0xFFFFDFFF
+#define S_0007C0_GUIDMA_BUSY(x) (((x) & 0x1) << 28)
+#define G_0007C0_GUIDMA_BUSY(x) (((x) >> 28) & 0x1)
+#define C_0007C0_GUIDMA_BUSY 0xEFFFFFFF
+#define S_0007C0_VIDDMA_BUSY(x) (((x) & 0x1) << 29)
+#define G_0007C0_VIDDMA_BUSY(x) (((x) >> 29) & 0x1)
+#define C_0007C0_VIDDMA_BUSY 0xDFFFFFFF
+#define S_0007C0_CMDSTRM_BUSY(x) (((x) & 0x1) << 30)
+#define G_0007C0_CMDSTRM_BUSY(x) (((x) >> 30) & 0x1)
+#define C_0007C0_CMDSTRM_BUSY 0xBFFFFFFF
+#define S_0007C0_CP_BUSY(x) (((x) & 0x1) << 31)
+#define G_0007C0_CP_BUSY(x) (((x) >> 31) & 0x1)
+#define C_0007C0_CP_BUSY 0x7FFFFFFF
#define R_000E40_RBBM_STATUS 0x000E40
#define S_000E40_CMDFIFO_AVAIL(x) (((x) & 0x7F) << 0)
#define G_000E40_CMDFIFO_AVAIL(x) (((x) >> 0) & 0x7F)
@@ -604,4 +662,53 @@
#define G_000E40_GUI_ACTIVE(x) (((x) >> 31) & 0x1)
#define C_000E40_GUI_ACTIVE 0x7FFFFFFF
+
+#define R_00000D_SCLK_CNTL 0x00000D
+#define S_00000D_SCLK_SRC_SEL(x) (((x) & 0x7) << 0)
+#define G_00000D_SCLK_SRC_SEL(x) (((x) >> 0) & 0x7)
+#define C_00000D_SCLK_SRC_SEL 0xFFFFFFF8
+#define S_00000D_TCLK_SRC_SEL(x) (((x) & 0x7) << 8)
+#define G_00000D_TCLK_SRC_SEL(x) (((x) >> 8) & 0x7)
+#define C_00000D_TCLK_SRC_SEL 0xFFFFF8FF
+#define S_00000D_FORCE_CP(x) (((x) & 0x1) << 16)
+#define G_00000D_FORCE_CP(x) (((x) >> 16) & 0x1)
+#define C_00000D_FORCE_CP 0xFFFEFFFF
+#define S_00000D_FORCE_HDP(x) (((x) & 0x1) << 17)
+#define G_00000D_FORCE_HDP(x) (((x) >> 17) & 0x1)
+#define C_00000D_FORCE_HDP 0xFFFDFFFF
+#define S_00000D_FORCE_DISP(x) (((x) & 0x1) << 18)
+#define G_00000D_FORCE_DISP(x) (((x) >> 18) & 0x1)
+#define C_00000D_FORCE_DISP 0xFFFBFFFF
+#define S_00000D_FORCE_TOP(x) (((x) & 0x1) << 19)
+#define G_00000D_FORCE_TOP(x) (((x) >> 19) & 0x1)
+#define C_00000D_FORCE_TOP 0xFFF7FFFF
+#define S_00000D_FORCE_E2(x) (((x) & 0x1) << 20)
+#define G_00000D_FORCE_E2(x) (((x) >> 20) & 0x1)
+#define C_00000D_FORCE_E2 0xFFEFFFFF
+#define S_00000D_FORCE_SE(x) (((x) & 0x1) << 21)
+#define G_00000D_FORCE_SE(x) (((x) >> 21) & 0x1)
+#define C_00000D_FORCE_SE 0xFFDFFFFF
+#define S_00000D_FORCE_IDCT(x) (((x) & 0x1) << 22)
+#define G_00000D_FORCE_IDCT(x) (((x) >> 22) & 0x1)
+#define C_00000D_FORCE_IDCT 0xFFBFFFFF
+#define S_00000D_FORCE_VIP(x) (((x) & 0x1) << 23)
+#define G_00000D_FORCE_VIP(x) (((x) >> 23) & 0x1)
+#define C_00000D_FORCE_VIP 0xFF7FFFFF
+#define S_00000D_FORCE_RE(x) (((x) & 0x1) << 24)
+#define G_00000D_FORCE_RE(x) (((x) >> 24) & 0x1)
+#define C_00000D_FORCE_RE 0xFEFFFFFF
+#define S_00000D_FORCE_PB(x) (((x) & 0x1) << 25)
+#define G_00000D_FORCE_PB(x) (((x) >> 25) & 0x1)
+#define C_00000D_FORCE_PB 0xFDFFFFFF
+#define S_00000D_FORCE_TAM(x) (((x) & 0x1) << 26)
+#define G_00000D_FORCE_TAM(x) (((x) >> 26) & 0x1)
+#define C_00000D_FORCE_TAM 0xFBFFFFFF
+#define S_00000D_FORCE_TDM(x) (((x) & 0x1) << 27)
+#define G_00000D_FORCE_TDM(x) (((x) >> 27) & 0x1)
+#define C_00000D_FORCE_TDM 0xF7FFFFFF
+#define S_00000D_FORCE_RB(x) (((x) & 0x1) << 28)
+#define G_00000D_FORCE_RB(x) (((x) >> 28) & 0x1)
+#define C_00000D_FORCE_RB 0xEFFFFFFF
+
+
#endif
diff --git a/drivers/gpu/drm/radeon/r200.c b/drivers/gpu/drm/radeon/r200.c
index cf7fea5ff2e5..eb740fc3549f 100644
--- a/drivers/gpu/drm/radeon/r200.c
+++ b/drivers/gpu/drm/radeon/r200.c
@@ -447,9 +447,8 @@ int r200_packet0_check(struct radeon_cs_parser *p,
return 0;
}
-int r200_init(struct radeon_device *rdev)
+void r200_set_safe_registers(struct radeon_device *rdev)
{
rdev->config.r100.reg_safe_bm = r200_reg_safe_bm;
rdev->config.r100.reg_safe_bm_size = ARRAY_SIZE(r200_reg_safe_bm);
- return 0;
}
diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c
index 1ebea8cc8c93..e08c4a8974ca 100644
--- a/drivers/gpu/drm/radeon/r300.c
+++ b/drivers/gpu/drm/radeon/r300.c
@@ -33,43 +33,16 @@
#include "radeon_drm.h"
#include "r100_track.h"
#include "r300d.h"
-
+#include "rv350d.h"
#include "r300_reg_safe.h"
-/* r300,r350,rv350,rv370,rv380 depends on : */
-void r100_hdp_reset(struct radeon_device *rdev);
-int r100_cp_reset(struct radeon_device *rdev);
-int r100_rb2d_reset(struct radeon_device *rdev);
-int r100_cp_init(struct radeon_device *rdev, unsigned ring_size);
-int r100_pci_gart_enable(struct radeon_device *rdev);
-void r100_mc_setup(struct radeon_device *rdev);
-void r100_mc_disable_clients(struct radeon_device *rdev);
-int r100_gui_wait_for_idle(struct radeon_device *rdev);
-int r100_cs_packet_parse(struct radeon_cs_parser *p,
- struct radeon_cs_packet *pkt,
- unsigned idx);
-int r100_cs_packet_parse_vline(struct radeon_cs_parser *p);
-int r100_cs_parse_packet0(struct radeon_cs_parser *p,
- struct radeon_cs_packet *pkt,
- const unsigned *auth, unsigned n,
- radeon_packet0_check_t check);
-int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p,
- struct radeon_cs_packet *pkt,
- struct radeon_object *robj);
-
-/* This files gather functions specifics to:
- * r300,r350,rv350,rv370,rv380
- *
- * Some of these functions might be used by newer ASICs.
- */
-void r300_gpu_init(struct radeon_device *rdev);
-int r300_mc_wait_for_idle(struct radeon_device *rdev);
-int rv370_debugfs_pcie_gart_info_init(struct radeon_device *rdev);
-
+/* This files gather functions specifics to: r300,r350,rv350,rv370,rv380 */
/*
* rv370,rv380 PCIE GART
*/
+static int rv370_debugfs_pcie_gart_info_init(struct radeon_device *rdev);
+
void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev)
{
uint32_t tmp;
@@ -182,59 +155,6 @@ void rv370_pcie_gart_fini(struct radeon_device *rdev)
radeon_gart_fini(rdev);
}
-/*
- * MC
- */
-int r300_mc_init(struct radeon_device *rdev)
-{
- int r;
-
- if (r100_debugfs_rbbm_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for RBBM !\n");
- }
-
- r300_gpu_init(rdev);
- r100_pci_gart_disable(rdev);
- if (rdev->flags & RADEON_IS_PCIE) {
- rv370_pcie_gart_disable(rdev);
- }
-
- /* Setup GPU memory space */
- rdev->mc.vram_location = 0xFFFFFFFFUL;
- rdev->mc.gtt_location = 0xFFFFFFFFUL;
- if (rdev->flags & RADEON_IS_AGP) {
- r = radeon_agp_init(rdev);
- if (r) {
- printk(KERN_WARNING "[drm] Disabling AGP\n");
- rdev->flags &= ~RADEON_IS_AGP;
- rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
- } else {
- rdev->mc.gtt_location = rdev->mc.agp_base;
- }
- }
- r = radeon_mc_setup(rdev);
- if (r) {
- return r;
- }
-
- /* Program GPU memory space */
- r100_mc_disable_clients(rdev);
- if (r300_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "Failed to wait MC idle while "
- "programming pipes. Bad things might happen.\n");
- }
- r100_mc_setup(rdev);
- return 0;
-}
-
-void r300_mc_fini(struct radeon_device *rdev)
-{
-}
-
-
-/*
- * Fence emission
- */
void r300_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence)
{
@@ -260,10 +180,6 @@ void r300_fence_ring_emit(struct radeon_device *rdev,
radeon_ring_write(rdev, RADEON_SW_INT_FIRE);
}
-
-/*
- * Global GPU functions
- */
int r300_copy_dma(struct radeon_device *rdev,
uint64_t src_offset,
uint64_t dst_offset,
@@ -582,11 +498,6 @@ void r300_vram_info(struct radeon_device *rdev)
r100_vram_init_sizes(rdev);
}
-
-/*
- * PCIE Lanes
- */
-
void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes)
{
uint32_t link_width_cntl, mask;
@@ -646,10 +557,6 @@ void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes)
}
-
-/*
- * Debugfs info
- */
#if defined(CONFIG_DEBUG_FS)
static int rv370_debugfs_pcie_gart_info(struct seq_file *m, void *data)
{
@@ -680,7 +587,7 @@ static struct drm_info_list rv370_pcie_gart_info_list[] = {
};
#endif
-int rv370_debugfs_pcie_gart_info_init(struct radeon_device *rdev)
+static int rv370_debugfs_pcie_gart_info_init(struct radeon_device *rdev)
{
#if defined(CONFIG_DEBUG_FS)
return radeon_debugfs_add_files(rdev, rv370_pcie_gart_info_list, 1);
@@ -689,10 +596,6 @@ int rv370_debugfs_pcie_gart_info_init(struct radeon_device *rdev)
#endif
}
-
-/*
- * CS functions
- */
static int r300_packet0_check(struct radeon_cs_parser *p,
struct radeon_cs_packet *pkt,
unsigned idx, unsigned reg)
@@ -1226,12 +1129,6 @@ void r300_set_reg_safe(struct radeon_device *rdev)
rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r300_reg_safe_bm);
}
-int r300_init(struct radeon_device *rdev)
-{
- r300_set_reg_safe(rdev);
- return 0;
-}
-
void r300_mc_program(struct radeon_device *rdev)
{
struct r100_mc_save save;
@@ -1265,3 +1162,198 @@ void r300_mc_program(struct radeon_device *rdev)
S_000148_MC_FB_TOP(rdev->mc.vram_end >> 16));
r100_mc_resume(rdev, &save);
}
+
+void r300_clock_startup(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ if (radeon_dynclks != -1 && radeon_dynclks)
+ radeon_legacy_set_clock_gating(rdev, 1);
+ /* We need to force on some of the block */
+ tmp = RREG32_PLL(R_00000D_SCLK_CNTL);
+ tmp |= S_00000D_FORCE_CP(1) | S_00000D_FORCE_VIP(1);
+ if ((rdev->family == CHIP_RV350) || (rdev->family == CHIP_RV380))
+ tmp |= S_00000D_FORCE_VAP(1);
+ WREG32_PLL(R_00000D_SCLK_CNTL, tmp);
+}
+
+static int r300_startup(struct radeon_device *rdev)
+{
+ int r;
+
+ r300_mc_program(rdev);
+ /* Resume clock */
+ r300_clock_startup(rdev);
+ /* Initialize GPU configuration (# pipes, ...) */
+ r300_gpu_init(rdev);
+ /* Initialize GART (initialize after TTM so we can allocate
+ * memory through TTM but finalize after TTM) */
+ if (rdev->flags & RADEON_IS_PCIE) {
+ r = rv370_pcie_gart_enable(rdev);
+ if (r)
+ return r;
+ }
+ if (rdev->flags & RADEON_IS_PCI) {
+ r = r100_pci_gart_enable(rdev);
+ if (r)
+ return r;
+ }
+ /* Enable IRQ */
+ rdev->irq.sw_int = true;
+ r100_irq_set(rdev);
+ /* 1M ring buffer */
+ r = r100_cp_init(rdev, 1024 * 1024);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ return r;
+ }
+ r = r100_wb_init(rdev);
+ if (r)
+ dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
+ r = r100_ib_init(rdev);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ return r;
+ }
+ return 0;
+}
+
+int r300_resume(struct radeon_device *rdev)
+{
+ /* Make sur GART are not working */
+ if (rdev->flags & RADEON_IS_PCIE)
+ rv370_pcie_gart_disable(rdev);
+ if (rdev->flags & RADEON_IS_PCI)
+ r100_pci_gart_disable(rdev);
+ /* Resume clock before doing reset */
+ r300_clock_startup(rdev);
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_reset(rdev)) {
+ dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
+ RREG32(R_000E40_RBBM_STATUS),
+ RREG32(R_0007C0_CP_STAT));
+ }
+ /* post */
+ radeon_combios_asic_init(rdev->ddev);
+ /* Resume clock after posting */
+ r300_clock_startup(rdev);
+ return r300_startup(rdev);
+}
+
+int r300_suspend(struct radeon_device *rdev)
+{
+ r100_cp_disable(rdev);
+ r100_wb_disable(rdev);
+ r100_irq_disable(rdev);
+ if (rdev->flags & RADEON_IS_PCIE)
+ rv370_pcie_gart_disable(rdev);
+ if (rdev->flags & RADEON_IS_PCI)
+ r100_pci_gart_disable(rdev);
+ return 0;
+}
+
+void r300_fini(struct radeon_device *rdev)
+{
+ r300_suspend(rdev);
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ radeon_gem_fini(rdev);
+ if (rdev->flags & RADEON_IS_PCIE)
+ rv370_pcie_gart_fini(rdev);
+ if (rdev->flags & RADEON_IS_PCI)
+ r100_pci_gart_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ radeon_fence_driver_fini(rdev);
+ radeon_object_fini(rdev);
+ radeon_atombios_fini(rdev);
+ kfree(rdev->bios);
+ rdev->bios = NULL;
+}
+
+int r300_init(struct radeon_device *rdev)
+{
+ int r;
+
+ /* Disable VGA */
+ r100_vga_render_disable(rdev);
+ /* Initialize scratch registers */
+ radeon_scratch_init(rdev);
+ /* Initialize surface registers */
+ radeon_surface_init(rdev);
+ /* TODO: disable VGA need to use VGA request */
+ /* BIOS*/
+ if (!radeon_get_bios(rdev)) {
+ if (ASIC_IS_AVIVO(rdev))
+ return -EINVAL;
+ }
+ if (rdev->is_atom_bios) {
+ dev_err(rdev->dev, "Expecting combios for RS400/RS480 GPU\n");
+ return -EINVAL;
+ } else {
+ r = radeon_combios_init(rdev);
+ if (r)
+ return r;
+ }
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_reset(rdev)) {
+ dev_warn(rdev->dev,
+ "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
+ RREG32(R_000E40_RBBM_STATUS),
+ RREG32(R_0007C0_CP_STAT));
+ }
+ /* check if cards are posted or not */
+ if (!radeon_card_posted(rdev) && rdev->bios) {
+ DRM_INFO("GPU not posted. posting now...\n");
+ radeon_combios_asic_init(rdev->ddev);
+ }
+ /* Set asic errata */
+ r300_errata(rdev);
+ /* Initialize clocks */
+ radeon_get_clock_info(rdev->ddev);
+ /* Get vram informations */
+ r300_vram_info(rdev);
+ /* Initialize memory controller (also test AGP) */
+ r = r420_mc_init(rdev);
+ if (r)
+ return r;
+ /* Fence driver */
+ r = radeon_fence_driver_init(rdev);
+ if (r)
+ return r;
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ /* Memory manager */
+ r = radeon_object_init(rdev);
+ if (r)
+ return r;
+ if (rdev->flags & RADEON_IS_PCIE) {
+ r = rv370_pcie_gart_init(rdev);
+ if (r)
+ return r;
+ }
+ if (rdev->flags & RADEON_IS_PCI) {
+ r = r100_pci_gart_init(rdev);
+ if (r)
+ return r;
+ }
+ r300_set_reg_safe(rdev);
+ rdev->accel_working = true;
+ r = r300_startup(rdev);
+ if (r) {
+ /* Somethings want wront with the accel init stop accel */
+ dev_err(rdev->dev, "Disabling GPU acceleration\n");
+ r300_suspend(rdev);
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ if (rdev->flags & RADEON_IS_PCIE)
+ rv370_pcie_gart_fini(rdev);
+ if (rdev->flags & RADEON_IS_PCI)
+ r100_pci_gart_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ rdev->accel_working = false;
+ }
+ return 0;
+}
diff --git a/drivers/gpu/drm/radeon/r300d.h b/drivers/gpu/drm/radeon/r300d.h
index d4fa3eb1074f..4c73114f0de9 100644
--- a/drivers/gpu/drm/radeon/r300d.h
+++ b/drivers/gpu/drm/radeon/r300d.h
@@ -96,6 +96,211 @@
#define S_000170_AGP_BASE_ADDR(x) (((x) & 0xFFFFFFFF) << 0)
#define G_000170_AGP_BASE_ADDR(x) (((x) >> 0) & 0xFFFFFFFF)
#define C_000170_AGP_BASE_ADDR 0x00000000
+#define R_0007C0_CP_STAT 0x0007C0
+#define S_0007C0_MRU_BUSY(x) (((x) & 0x1) << 0)
+#define G_0007C0_MRU_BUSY(x) (((x) >> 0) & 0x1)
+#define C_0007C0_MRU_BUSY 0xFFFFFFFE
+#define S_0007C0_MWU_BUSY(x) (((x) & 0x1) << 1)
+#define G_0007C0_MWU_BUSY(x) (((x) >> 1) & 0x1)
+#define C_0007C0_MWU_BUSY 0xFFFFFFFD
+#define S_0007C0_RSIU_BUSY(x) (((x) & 0x1) << 2)
+#define G_0007C0_RSIU_BUSY(x) (((x) >> 2) & 0x1)
+#define C_0007C0_RSIU_BUSY 0xFFFFFFFB
+#define S_0007C0_RCIU_BUSY(x) (((x) & 0x1) << 3)
+#define G_0007C0_RCIU_BUSY(x) (((x) >> 3) & 0x1)
+#define C_0007C0_RCIU_BUSY 0xFFFFFFF7
+#define S_0007C0_CSF_PRIMARY_BUSY(x) (((x) & 0x1) << 9)
+#define G_0007C0_CSF_PRIMARY_BUSY(x) (((x) >> 9) & 0x1)
+#define C_0007C0_CSF_PRIMARY_BUSY 0xFFFFFDFF
+#define S_0007C0_CSF_INDIRECT_BUSY(x) (((x) & 0x1) << 10)
+#define G_0007C0_CSF_INDIRECT_BUSY(x) (((x) >> 10) & 0x1)
+#define C_0007C0_CSF_INDIRECT_BUSY 0xFFFFFBFF
+#define S_0007C0_CSQ_PRIMARY_BUSY(x) (((x) & 0x1) << 11)
+#define G_0007C0_CSQ_PRIMARY_BUSY(x) (((x) >> 11) & 0x1)
+#define C_0007C0_CSQ_PRIMARY_BUSY 0xFFFFF7FF
+#define S_0007C0_CSQ_INDIRECT_BUSY(x) (((x) & 0x1) << 12)
+#define G_0007C0_CSQ_INDIRECT_BUSY(x) (((x) >> 12) & 0x1)
+#define C_0007C0_CSQ_INDIRECT_BUSY 0xFFFFEFFF
+#define S_0007C0_CSI_BUSY(x) (((x) & 0x1) << 13)
+#define G_0007C0_CSI_BUSY(x) (((x) >> 13) & 0x1)
+#define C_0007C0_CSI_BUSY 0xFFFFDFFF
+#define S_0007C0_CSF_INDIRECT2_BUSY(x) (((x) & 0x1) << 14)
+#define G_0007C0_CSF_INDIRECT2_BUSY(x) (((x) >> 14) & 0x1)
+#define C_0007C0_CSF_INDIRECT2_BUSY 0xFFFFBFFF
+#define S_0007C0_CSQ_INDIRECT2_BUSY(x) (((x) & 0x1) << 15)
+#define G_0007C0_CSQ_INDIRECT2_BUSY(x) (((x) >> 15) & 0x1)
+#define C_0007C0_CSQ_INDIRECT2_BUSY 0xFFFF7FFF
+#define S_0007C0_GUIDMA_BUSY(x) (((x) & 0x1) << 28)
+#define G_0007C0_GUIDMA_BUSY(x) (((x) >> 28) & 0x1)
+#define C_0007C0_GUIDMA_BUSY 0xEFFFFFFF
+#define S_0007C0_VIDDMA_BUSY(x) (((x) & 0x1) << 29)
+#define G_0007C0_VIDDMA_BUSY(x) (((x) >> 29) & 0x1)
+#define C_0007C0_VIDDMA_BUSY 0xDFFFFFFF
+#define S_0007C0_CMDSTRM_BUSY(x) (((x) & 0x1) << 30)
+#define G_0007C0_CMDSTRM_BUSY(x) (((x) >> 30) & 0x1)
+#define C_0007C0_CMDSTRM_BUSY 0xBFFFFFFF
+#define S_0007C0_CP_BUSY(x) (((x) & 0x1) << 31)
+#define G_0007C0_CP_BUSY(x) (((x) >> 31) & 0x1)
+#define C_0007C0_CP_BUSY 0x7FFFFFFF
+#define R_000E40_RBBM_STATUS 0x000E40
+#define S_000E40_CMDFIFO_AVAIL(x) (((x) & 0x7F) << 0)
+#define G_000E40_CMDFIFO_AVAIL(x) (((x) >> 0) & 0x7F)
+#define C_000E40_CMDFIFO_AVAIL 0xFFFFFF80
+#define S_000E40_HIRQ_ON_RBB(x) (((x) & 0x1) << 8)
+#define G_000E40_HIRQ_ON_RBB(x) (((x) >> 8) & 0x1)
+#define C_000E40_HIRQ_ON_RBB 0xFFFFFEFF
+#define S_000E40_CPRQ_ON_RBB(x) (((x) & 0x1) << 9)
+#define G_000E40_CPRQ_ON_RBB(x) (((x) >> 9) & 0x1)
+#define C_000E40_CPRQ_ON_RBB 0xFFFFFDFF
+#define S_000E40_CFRQ_ON_RBB(x) (((x) & 0x1) << 10)
+#define G_000E40_CFRQ_ON_RBB(x) (((x) >> 10) & 0x1)
+#define C_000E40_CFRQ_ON_RBB 0xFFFFFBFF
+#define S_000E40_HIRQ_IN_RTBUF(x) (((x) & 0x1) << 11)
+#define G_000E40_HIRQ_IN_RTBUF(x) (((x) >> 11) & 0x1)
+#define C_000E40_HIRQ_IN_RTBUF 0xFFFFF7FF
+#define S_000E40_CPRQ_IN_RTBUF(x) (((x) & 0x1) << 12)
+#define G_000E40_CPRQ_IN_RTBUF(x) (((x) >> 12) & 0x1)
+#define C_000E40_CPRQ_IN_RTBUF 0xFFFFEFFF
+#define S_000E40_CFRQ_IN_RTBUF(x) (((x) & 0x1) << 13)
+#define G_000E40_CFRQ_IN_RTBUF(x) (((x) >> 13) & 0x1)
+#define C_000E40_CFRQ_IN_RTBUF 0xFFFFDFFF
+#define S_000E40_CF_PIPE_BUSY(x) (((x) & 0x1) << 14)
+#define G_000E40_CF_PIPE_BUSY(x) (((x) >> 14) & 0x1)
+#define C_000E40_CF_PIPE_BUSY 0xFFFFBFFF
+#define S_000E40_ENG_EV_BUSY(x) (((x) & 0x1) << 15)
+#define G_000E40_ENG_EV_BUSY(x) (((x) >> 15) & 0x1)
+#define C_000E40_ENG_EV_BUSY 0xFFFF7FFF
+#define S_000E40_CP_CMDSTRM_BUSY(x) (((x) & 0x1) << 16)
+#define G_000E40_CP_CMDSTRM_BUSY(x) (((x) >> 16) & 0x1)
+#define C_000E40_CP_CMDSTRM_BUSY 0xFFFEFFFF
+#define S_000E40_E2_BUSY(x) (((x) & 0x1) << 17)
+#define G_000E40_E2_BUSY(x) (((x) >> 17) & 0x1)
+#define C_000E40_E2_BUSY 0xFFFDFFFF
+#define S_000E40_RB2D_BUSY(x) (((x) & 0x1) << 18)
+#define G_000E40_RB2D_BUSY(x) (((x) >> 18) & 0x1)
+#define C_000E40_RB2D_BUSY 0xFFFBFFFF
+#define S_000E40_RB3D_BUSY(x) (((x) & 0x1) << 19)
+#define G_000E40_RB3D_BUSY(x) (((x) >> 19) & 0x1)
+#define C_000E40_RB3D_BUSY 0xFFF7FFFF
+#define S_000E40_VAP_BUSY(x) (((x) & 0x1) << 20)
+#define G_000E40_VAP_BUSY(x) (((x) >> 20) & 0x1)
+#define C_000E40_VAP_BUSY 0xFFEFFFFF
+#define S_000E40_RE_BUSY(x) (((x) & 0x1) << 21)
+#define G_000E40_RE_BUSY(x) (((x) >> 21) & 0x1)
+#define C_000E40_RE_BUSY 0xFFDFFFFF
+#define S_000E40_TAM_BUSY(x) (((x) & 0x1) << 22)
+#define G_000E40_TAM_BUSY(x) (((x) >> 22) & 0x1)
+#define C_000E40_TAM_BUSY 0xFFBFFFFF
+#define S_000E40_TDM_BUSY(x) (((x) & 0x1) << 23)
+#define G_000E40_TDM_BUSY(x) (((x) >> 23) & 0x1)
+#define C_000E40_TDM_BUSY 0xFF7FFFFF
+#define S_000E40_PB_BUSY(x) (((x) & 0x1) << 24)
+#define G_000E40_PB_BUSY(x) (((x) >> 24) & 0x1)
+#define C_000E40_PB_BUSY 0xFEFFFFFF
+#define S_000E40_TIM_BUSY(x) (((x) & 0x1) << 25)
+#define G_000E40_TIM_BUSY(x) (((x) >> 25) & 0x1)
+#define C_000E40_TIM_BUSY 0xFDFFFFFF
+#define S_000E40_GA_BUSY(x) (((x) & 0x1) << 26)
+#define G_000E40_GA_BUSY(x) (((x) >> 26) & 0x1)
+#define C_000E40_GA_BUSY 0xFBFFFFFF
+#define S_000E40_CBA2D_BUSY(x) (((x) & 0x1) << 27)
+#define G_000E40_CBA2D_BUSY(x) (((x) >> 27) & 0x1)
+#define C_000E40_CBA2D_BUSY 0xF7FFFFFF
+#define S_000E40_GUI_ACTIVE(x) (((x) & 0x1) << 31)
+#define G_000E40_GUI_ACTIVE(x) (((x) >> 31) & 0x1)
+#define C_000E40_GUI_ACTIVE 0x7FFFFFFF
+#define R_00000D_SCLK_CNTL 0x00000D
+#define S_00000D_SCLK_SRC_SEL(x) (((x) & 0x7) << 0)
+#define G_00000D_SCLK_SRC_SEL(x) (((x) >> 0) & 0x7)
+#define C_00000D_SCLK_SRC_SEL 0xFFFFFFF8
+#define S_00000D_CP_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 3)
+#define G_00000D_CP_MAX_DYN_STOP_LAT(x) (((x) >> 3) & 0x1)
+#define C_00000D_CP_MAX_DYN_STOP_LAT 0xFFFFFFF7
+#define S_00000D_HDP_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 4)
+#define G_00000D_HDP_MAX_DYN_STOP_LAT(x) (((x) >> 4) & 0x1)
+#define C_00000D_HDP_MAX_DYN_STOP_LAT 0xFFFFFFEF
+#define S_00000D_TV_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 5)
+#define G_00000D_TV_MAX_DYN_STOP_LAT(x) (((x) >> 5) & 0x1)
+#define C_00000D_TV_MAX_DYN_STOP_LAT 0xFFFFFFDF
+#define S_00000D_E2_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 6)
+#define G_00000D_E2_MAX_DYN_STOP_LAT(x) (((x) >> 6) & 0x1)
+#define C_00000D_E2_MAX_DYN_STOP_LAT 0xFFFFFFBF
+#define S_00000D_SE_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 7)
+#define G_00000D_SE_MAX_DYN_STOP_LAT(x) (((x) >> 7) & 0x1)
+#define C_00000D_SE_MAX_DYN_STOP_LAT 0xFFFFFF7F
+#define S_00000D_IDCT_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 8)
+#define G_00000D_IDCT_MAX_DYN_STOP_LAT(x) (((x) >> 8) & 0x1)
+#define C_00000D_IDCT_MAX_DYN_STOP_LAT 0xFFFFFEFF
+#define S_00000D_VIP_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 9)
+#define G_00000D_VIP_MAX_DYN_STOP_LAT(x) (((x) >> 9) & 0x1)
+#define C_00000D_VIP_MAX_DYN_STOP_LAT 0xFFFFFDFF
+#define S_00000D_RE_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 10)
+#define G_00000D_RE_MAX_DYN_STOP_LAT(x) (((x) >> 10) & 0x1)
+#define C_00000D_RE_MAX_DYN_STOP_LAT 0xFFFFFBFF
+#define S_00000D_PB_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 11)
+#define G_00000D_PB_MAX_DYN_STOP_LAT(x) (((x) >> 11) & 0x1)
+#define C_00000D_PB_MAX_DYN_STOP_LAT 0xFFFFF7FF
+#define S_00000D_TAM_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 12)
+#define G_00000D_TAM_MAX_DYN_STOP_LAT(x) (((x) >> 12) & 0x1)
+#define C_00000D_TAM_MAX_DYN_STOP_LAT 0xFFFFEFFF
+#define S_00000D_TDM_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 13)
+#define G_00000D_TDM_MAX_DYN_STOP_LAT(x) (((x) >> 13) & 0x1)
+#define C_00000D_TDM_MAX_DYN_STOP_LAT 0xFFFFDFFF
+#define S_00000D_RB_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 14)
+#define G_00000D_RB_MAX_DYN_STOP_LAT(x) (((x) >> 14) & 0x1)
+#define C_00000D_RB_MAX_DYN_STOP_LAT 0xFFFFBFFF
+#define S_00000D_FORCE_DISP2(x) (((x) & 0x1) << 15)
+#define G_00000D_FORCE_DISP2(x) (((x) >> 15) & 0x1)
+#define C_00000D_FORCE_DISP2 0xFFFF7FFF
+#define S_00000D_FORCE_CP(x) (((x) & 0x1) << 16)
+#define G_00000D_FORCE_CP(x) (((x) >> 16) & 0x1)
+#define C_00000D_FORCE_CP 0xFFFEFFFF
+#define S_00000D_FORCE_HDP(x) (((x) & 0x1) << 17)
+#define G_00000D_FORCE_HDP(x) (((x) >> 17) & 0x1)
+#define C_00000D_FORCE_HDP 0xFFFDFFFF
+#define S_00000D_FORCE_DISP1(x) (((x) & 0x1) << 18)
+#define G_00000D_FORCE_DISP1(x) (((x) >> 18) & 0x1)
+#define C_00000D_FORCE_DISP1 0xFFFBFFFF
+#define S_00000D_FORCE_TOP(x) (((x) & 0x1) << 19)
+#define G_00000D_FORCE_TOP(x) (((x) >> 19) & 0x1)
+#define C_00000D_FORCE_TOP 0xFFF7FFFF
+#define S_00000D_FORCE_E2(x) (((x) & 0x1) << 20)
+#define G_00000D_FORCE_E2(x) (((x) >> 20) & 0x1)
+#define C_00000D_FORCE_E2 0xFFEFFFFF
+#define S_00000D_FORCE_SE(x) (((x) & 0x1) << 21)
+#define G_00000D_FORCE_SE(x) (((x) >> 21) & 0x1)
+#define C_00000D_FORCE_SE 0xFFDFFFFF
+#define S_00000D_FORCE_IDCT(x) (((x) & 0x1) << 22)
+#define G_00000D_FORCE_IDCT(x) (((x) >> 22) & 0x1)
+#define C_00000D_FORCE_IDCT 0xFFBFFFFF
+#define S_00000D_FORCE_VIP(x) (((x) & 0x1) << 23)
+#define G_00000D_FORCE_VIP(x) (((x) >> 23) & 0x1)
+#define C_00000D_FORCE_VIP 0xFF7FFFFF
+#define S_00000D_FORCE_RE(x) (((x) & 0x1) << 24)
+#define G_00000D_FORCE_RE(x) (((x) >> 24) & 0x1)
+#define C_00000D_FORCE_RE 0xFEFFFFFF
+#define S_00000D_FORCE_PB(x) (((x) & 0x1) << 25)
+#define G_00000D_FORCE_PB(x) (((x) >> 25) & 0x1)
+#define C_00000D_FORCE_PB 0xFDFFFFFF
+#define S_00000D_FORCE_TAM(x) (((x) & 0x1) << 26)
+#define G_00000D_FORCE_TAM(x) (((x) >> 26) & 0x1)
+#define C_00000D_FORCE_TAM 0xFBFFFFFF
+#define S_00000D_FORCE_TDM(x) (((x) & 0x1) << 27)
+#define G_00000D_FORCE_TDM(x) (((x) >> 27) & 0x1)
+#define C_00000D_FORCE_TDM 0xF7FFFFFF
+#define S_00000D_FORCE_RB(x) (((x) & 0x1) << 28)
+#define G_00000D_FORCE_RB(x) (((x) >> 28) & 0x1)
+#define C_00000D_FORCE_RB 0xEFFFFFFF
+#define S_00000D_FORCE_TV_SCLK(x) (((x) & 0x1) << 29)
+#define G_00000D_FORCE_TV_SCLK(x) (((x) >> 29) & 0x1)
+#define C_00000D_FORCE_TV_SCLK 0xDFFFFFFF
+#define S_00000D_FORCE_SUBPIC(x) (((x) & 0x1) << 30)
+#define G_00000D_FORCE_SUBPIC(x) (((x) >> 30) & 0x1)
+#define C_00000D_FORCE_SUBPIC 0xBFFFFFFF
+#define S_00000D_FORCE_OV0(x) (((x) & 0x1) << 31)
+#define G_00000D_FORCE_OV0(x) (((x) >> 31) & 0x1)
+#define C_00000D_FORCE_OV0 0x7FFFFFFF
+
#endif
diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c
index 49a2fdc57d27..5c7fe52de30e 100644
--- a/drivers/gpu/drm/radeon/r420.c
+++ b/drivers/gpu/drm/radeon/r420.c
@@ -155,6 +155,9 @@ static void r420_debugfs(struct radeon_device *rdev)
static void r420_clock_resume(struct radeon_device *rdev)
{
u32 sclk_cntl;
+
+ if (radeon_dynclks != -1 && radeon_dynclks)
+ radeon_atom_set_clock_gating(rdev, 1);
sclk_cntl = RREG32_PLL(R_00000D_SCLK_CNTL);
sclk_cntl |= S_00000D_FORCE_CP(1) | S_00000D_FORCE_VIP(1);
if (rdev->family == CHIP_R420)
@@ -167,6 +170,8 @@ static int r420_startup(struct radeon_device *rdev)
int r;
r300_mc_program(rdev);
+ /* Resume clock */
+ r420_clock_resume(rdev);
/* Initialize GART (initialize after TTM so we can allocate
* memory through TTM but finalize after TTM) */
if (rdev->flags & RADEON_IS_PCIE) {
@@ -267,7 +272,6 @@ int r420_init(struct radeon_device *rdev)
{
int r;
- rdev->new_init_path = true;
/* Initialize scratch registers */
radeon_scratch_init(rdev);
/* Initialize surface registers */
diff --git a/drivers/gpu/drm/radeon/r420d.h b/drivers/gpu/drm/radeon/r420d.h
index a48a7db1e2aa..fc78d31a0b4a 100644
--- a/drivers/gpu/drm/radeon/r420d.h
+++ b/drivers/gpu/drm/radeon/r420d.h
@@ -212,9 +212,9 @@
#define S_00000D_FORCE_E2(x) (((x) & 0x1) << 20)
#define G_00000D_FORCE_E2(x) (((x) >> 20) & 0x1)
#define C_00000D_FORCE_E2 0xFFEFFFFF
-#define S_00000D_FORCE_SE(x) (((x) & 0x1) << 21)
-#define G_00000D_FORCE_SE(x) (((x) >> 21) & 0x1)
-#define C_00000D_FORCE_SE 0xFFDFFFFF
+#define S_00000D_FORCE_VAP(x) (((x) & 0x1) << 21)
+#define G_00000D_FORCE_VAP(x) (((x) >> 21) & 0x1)
+#define C_00000D_FORCE_VAP 0xFFDFFFFF
#define S_00000D_FORCE_IDCT(x) (((x) & 0x1) << 22)
#define G_00000D_FORCE_IDCT(x) (((x) >> 22) & 0x1)
#define C_00000D_FORCE_IDCT 0xFFBFFFFF
@@ -224,24 +224,24 @@
#define S_00000D_FORCE_RE(x) (((x) & 0x1) << 24)
#define G_00000D_FORCE_RE(x) (((x) >> 24) & 0x1)
#define C_00000D_FORCE_RE 0xFEFFFFFF
-#define S_00000D_FORCE_PB(x) (((x) & 0x1) << 25)
-#define G_00000D_FORCE_PB(x) (((x) >> 25) & 0x1)
-#define C_00000D_FORCE_PB 0xFDFFFFFF
+#define S_00000D_FORCE_SR(x) (((x) & 0x1) << 25)
+#define G_00000D_FORCE_SR(x) (((x) >> 25) & 0x1)
+#define C_00000D_FORCE_SR 0xFDFFFFFF
#define S_00000D_FORCE_PX(x) (((x) & 0x1) << 26)
#define G_00000D_FORCE_PX(x) (((x) >> 26) & 0x1)
#define C_00000D_FORCE_PX 0xFBFFFFFF
#define S_00000D_FORCE_TX(x) (((x) & 0x1) << 27)
#define G_00000D_FORCE_TX(x) (((x) >> 27) & 0x1)
#define C_00000D_FORCE_TX 0xF7FFFFFF
-#define S_00000D_FORCE_RB(x) (((x) & 0x1) << 28)
-#define G_00000D_FORCE_RB(x) (((x) >> 28) & 0x1)
-#define C_00000D_FORCE_RB 0xEFFFFFFF
+#define S_00000D_FORCE_US(x) (((x) & 0x1) << 28)
+#define G_00000D_FORCE_US(x) (((x) >> 28) & 0x1)
+#define C_00000D_FORCE_US 0xEFFFFFFF
#define S_00000D_FORCE_TV_SCLK(x) (((x) & 0x1) << 29)
#define G_00000D_FORCE_TV_SCLK(x) (((x) >> 29) & 0x1)
#define C_00000D_FORCE_TV_SCLK 0xDFFFFFFF
-#define S_00000D_FORCE_SUBPIC(x) (((x) & 0x1) << 30)
-#define G_00000D_FORCE_SUBPIC(x) (((x) >> 30) & 0x1)
-#define C_00000D_FORCE_SUBPIC 0xBFFFFFFF
+#define S_00000D_FORCE_SU(x) (((x) & 0x1) << 30)
+#define G_00000D_FORCE_SU(x) (((x) >> 30) & 0x1)
+#define C_00000D_FORCE_SU 0xBFFFFFFF
#define S_00000D_FORCE_OV0(x) (((x) & 0x1) << 31)
#define G_00000D_FORCE_OV0(x) (((x) >> 31) & 0x1)
#define C_00000D_FORCE_OV0 0x7FFFFFFF
diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c
index 0bf13fccdaf2..a555b7b19b48 100644
--- a/drivers/gpu/drm/radeon/r520.c
+++ b/drivers/gpu/drm/radeon/r520.c
@@ -186,7 +186,7 @@ static int r520_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
rdev->irq.sw_int = true;
- r100_irq_set(rdev);
+ rs600_irq_set(rdev);
/* 1M ring buffer */
r = r100_cp_init(rdev, 1024 * 1024);
if (r) {
@@ -228,7 +228,6 @@ int r520_init(struct radeon_device *rdev)
{
int r;
- rdev->new_init_path = true;
/* Initialize scratch registers */
radeon_scratch_init(rdev);
/* Initialize surface registers */
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 2e4e60edbff4..609719490ec2 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -65,16 +65,11 @@ MODULE_FIRMWARE("radeon/RV710_me.bin");
int r600_debugfs_mc_info_init(struct radeon_device *rdev);
-/* This files gather functions specifics to:
- * r600,rv610,rv630,rv620,rv635,rv670
- *
- * Some of these functions might be used by newer ASICs.
- */
+/* r600,rv610,rv630,rv620,rv635,rv670 */
int r600_mc_wait_for_idle(struct radeon_device *rdev);
void r600_gpu_init(struct radeon_device *rdev);
void r600_fini(struct radeon_device *rdev);
-
/*
* R600 PCIE GART
*/
@@ -168,7 +163,7 @@ int r600_pcie_gart_enable(struct radeon_device *rdev)
WREG32(MC_VM_L1_TLB_MCB_RD_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE);
WREG32(MC_VM_L1_TLB_MCB_WR_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE);
WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
- WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, (rdev->mc.gtt_end - 1) >> 12);
+ WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12);
WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12);
WREG32(VM_CONTEXT0_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
RANGE_PROTECTION_FAULT_ENABLE_DEFAULT);
@@ -225,6 +220,40 @@ void r600_pcie_gart_fini(struct radeon_device *rdev)
radeon_gart_fini(rdev);
}
+void r600_agp_enable(struct radeon_device *rdev)
+{
+ u32 tmp;
+ int i;
+
+ /* Setup L2 cache */
+ WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING |
+ ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+ EFFECTIVE_L2_QUEUE_SIZE(7));
+ WREG32(VM_L2_CNTL2, 0);
+ WREG32(VM_L2_CNTL3, BANK_SELECT_0(0) | BANK_SELECT_1(1));
+ /* Setup TLB control */
+ tmp = ENABLE_L1_TLB | ENABLE_L1_FRAGMENT_PROCESSING |
+ SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+ EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5) |
+ ENABLE_WAIT_L2_QUERY;
+ WREG32(MC_VM_L1_TLB_MCB_RD_SYS_CNTL, tmp);
+ WREG32(MC_VM_L1_TLB_MCB_WR_SYS_CNTL, tmp);
+ WREG32(MC_VM_L1_TLB_MCB_RD_HDP_CNTL, tmp | ENABLE_L1_STRICT_ORDERING);
+ WREG32(MC_VM_L1_TLB_MCB_WR_HDP_CNTL, tmp);
+ WREG32(MC_VM_L1_TLB_MCD_RD_A_CNTL, tmp);
+ WREG32(MC_VM_L1_TLB_MCD_WR_A_CNTL, tmp);
+ WREG32(MC_VM_L1_TLB_MCD_RD_B_CNTL, tmp);
+ WREG32(MC_VM_L1_TLB_MCD_WR_B_CNTL, tmp);
+ WREG32(MC_VM_L1_TLB_MCB_RD_GFX_CNTL, tmp);
+ WREG32(MC_VM_L1_TLB_MCB_WR_GFX_CNTL, tmp);
+ WREG32(MC_VM_L1_TLB_MCB_RD_PDMA_CNTL, tmp);
+ WREG32(MC_VM_L1_TLB_MCB_WR_PDMA_CNTL, tmp);
+ WREG32(MC_VM_L1_TLB_MCB_RD_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE);
+ WREG32(MC_VM_L1_TLB_MCB_WR_SEM_CNTL, tmp | ENABLE_SEMAPHORE_MODE);
+ for (i = 0; i < 7; i++)
+ WREG32(VM_CONTEXT0_CNTL + (i * 4), 0);
+}
+
int r600_mc_wait_for_idle(struct radeon_device *rdev)
{
unsigned i;
@@ -240,14 +269,9 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev)
return -1;
}
-static void r600_mc_resume(struct radeon_device *rdev)
+static void r600_mc_program(struct radeon_device *rdev)
{
- u32 d1vga_control, d2vga_control;
- u32 vga_render_control, vga_hdp_control;
- u32 d1crtc_control, d2crtc_control;
- u32 new_d1grph_primary, new_d1grph_secondary;
- u32 new_d2grph_primary, new_d2grph_secondary;
- u64 old_vram_start;
+ struct rv515_mc_save save;
u32 tmp;
int i, j;
@@ -261,85 +285,51 @@ static void r600_mc_resume(struct radeon_device *rdev)
}
WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0);
- d1vga_control = RREG32(D1VGA_CONTROL);
- d2vga_control = RREG32(D2VGA_CONTROL);
- vga_render_control = RREG32(VGA_RENDER_CONTROL);
- vga_hdp_control = RREG32(VGA_HDP_CONTROL);
- d1crtc_control = RREG32(D1CRTC_CONTROL);
- d2crtc_control = RREG32(D2CRTC_CONTROL);
- old_vram_start = (u64)(RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24;
- new_d1grph_primary = RREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS);
- new_d1grph_secondary = RREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS);
- new_d1grph_primary += rdev->mc.vram_start - old_vram_start;
- new_d1grph_secondary += rdev->mc.vram_start - old_vram_start;
- new_d2grph_primary = RREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS);
- new_d2grph_secondary = RREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS);
- new_d2grph_primary += rdev->mc.vram_start - old_vram_start;
- new_d2grph_secondary += rdev->mc.vram_start - old_vram_start;
-
- /* Stop all video */
- WREG32(D1VGA_CONTROL, 0);
- WREG32(D2VGA_CONTROL, 0);
- WREG32(VGA_RENDER_CONTROL, 0);
- WREG32(D1CRTC_UPDATE_LOCK, 1);
- WREG32(D2CRTC_UPDATE_LOCK, 1);
- WREG32(D1CRTC_CONTROL, 0);
- WREG32(D2CRTC_CONTROL, 0);
- WREG32(D1CRTC_UPDATE_LOCK, 0);
- WREG32(D2CRTC_UPDATE_LOCK, 0);
-
- mdelay(1);
+ rv515_mc_stop(rdev, &save);
if (r600_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "[drm] MC not idle !\n");
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
-
- /* Lockout access through VGA aperture*/
+ /* Lockout access through VGA aperture (doesn't exist before R600) */
WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE);
-
/* Update configuration */
- WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.vram_start >> 12);
- WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, (rdev->mc.vram_end - 1) >> 12);
+ if (rdev->flags & RADEON_IS_AGP) {
+ if (rdev->mc.vram_start < rdev->mc.gtt_start) {
+ /* VRAM before AGP */
+ WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+ rdev->mc.vram_start >> 12);
+ WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+ rdev->mc.gtt_end >> 12);
+ } else {
+ /* VRAM after AGP */
+ WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+ rdev->mc.gtt_start >> 12);
+ WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+ rdev->mc.vram_end >> 12);
+ }
+ } else {
+ WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.vram_start >> 12);
+ WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, rdev->mc.vram_end >> 12);
+ }
WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0);
- tmp = (((rdev->mc.vram_end - 1) >> 24) & 0xFFFF) << 16;
+ tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16;
tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF);
WREG32(MC_VM_FB_LOCATION, tmp);
WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8));
WREG32(HDP_NONSURFACE_INFO, (2 << 7));
- WREG32(HDP_NONSURFACE_SIZE, (rdev->mc.mc_vram_size - 1) | 0x3FF);
+ WREG32(HDP_NONSURFACE_SIZE, rdev->mc.mc_vram_size | 0x3FF);
if (rdev->flags & RADEON_IS_AGP) {
- WREG32(MC_VM_AGP_TOP, (rdev->mc.gtt_end - 1) >> 16);
- WREG32(MC_VM_AGP_BOT, rdev->mc.gtt_start >> 16);
+ WREG32(MC_VM_AGP_TOP, rdev->mc.gtt_end >> 22);
+ WREG32(MC_VM_AGP_BOT, rdev->mc.gtt_start >> 22);
WREG32(MC_VM_AGP_BASE, rdev->mc.agp_base >> 22);
} else {
WREG32(MC_VM_AGP_BASE, 0);
WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF);
WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF);
}
- WREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS, new_d1grph_primary);
- WREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS, new_d1grph_secondary);
- WREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS, new_d2grph_primary);
- WREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS, new_d2grph_secondary);
- WREG32(VGA_MEMORY_BASE_ADDRESS, rdev->mc.vram_start);
-
- /* Unlock host access */
- WREG32(VGA_HDP_CONTROL, vga_hdp_control);
-
- mdelay(1);
if (r600_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "[drm] MC not idle !\n");
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
-
- /* Restore video state */
- WREG32(D1CRTC_UPDATE_LOCK, 1);
- WREG32(D2CRTC_UPDATE_LOCK, 1);
- WREG32(D1CRTC_CONTROL, d1crtc_control);
- WREG32(D2CRTC_CONTROL, d2crtc_control);
- WREG32(D1CRTC_UPDATE_LOCK, 0);
- WREG32(D2CRTC_UPDATE_LOCK, 0);
- WREG32(D1VGA_CONTROL, d1vga_control);
- WREG32(D2VGA_CONTROL, d2vga_control);
- WREG32(VGA_RENDER_CONTROL, vga_render_control);
-
+ rv515_mc_resume(rdev, &save);
/* we need to own VRAM, so turn off the VGA renderer here
* to stop it overwriting our objects */
rv515_vga_render_disable(rdev);
@@ -445,9 +435,9 @@ int r600_mc_init(struct radeon_device *rdev)
}
}
rdev->mc.vram_start = rdev->mc.vram_location;
- rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size;
+ rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
rdev->mc.gtt_start = rdev->mc.gtt_location;
- rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size;
+ rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
/* FIXME: we should enforce default clock in case GPU is not in
* default setup
*/
@@ -463,6 +453,7 @@ int r600_mc_init(struct radeon_device *rdev)
*/
int r600_gpu_soft_reset(struct radeon_device *rdev)
{
+ struct rv515_mc_save save;
u32 grbm_busy_mask = S_008010_VC_BUSY(1) | S_008010_VGT_BUSY_NO_DMA(1) |
S_008010_VGT_BUSY(1) | S_008010_TA03_BUSY(1) |
S_008010_TC_BUSY(1) | S_008010_SX_BUSY(1) |
@@ -480,13 +471,25 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
S_008014_CB0_BUSY(1) | S_008014_CB1_BUSY(1) |
S_008014_CB2_BUSY(1) | S_008014_CB3_BUSY(1);
u32 srbm_reset = 0;
+ u32 tmp;
+ dev_info(rdev->dev, "GPU softreset \n");
+ dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n",
+ RREG32(R_008010_GRBM_STATUS));
+ dev_info(rdev->dev, " R_008014_GRBM_STATUS2=0x%08X\n",
+ RREG32(R_008014_GRBM_STATUS2));
+ dev_info(rdev->dev, " R_000E50_SRBM_STATUS=0x%08X\n",
+ RREG32(R_000E50_SRBM_STATUS));
+ rv515_mc_stop(rdev, &save);
+ if (r600_mc_wait_for_idle(rdev)) {
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+ }
/* Disable CP parsing/prefetching */
WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(0xff));
/* Check if any of the rendering block is busy and reset it */
if ((RREG32(R_008010_GRBM_STATUS) & grbm_busy_mask) ||
(RREG32(R_008014_GRBM_STATUS2) & grbm2_busy_mask)) {
- WREG32(R_008020_GRBM_SOFT_RESET, S_008020_SOFT_RESET_CR(1) |
+ tmp = S_008020_SOFT_RESET_CR(1) |
S_008020_SOFT_RESET_DB(1) |
S_008020_SOFT_RESET_CB(1) |
S_008020_SOFT_RESET_PA(1) |
@@ -498,14 +501,18 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
S_008020_SOFT_RESET_TC(1) |
S_008020_SOFT_RESET_TA(1) |
S_008020_SOFT_RESET_VC(1) |
- S_008020_SOFT_RESET_VGT(1));
+ S_008020_SOFT_RESET_VGT(1);
+ dev_info(rdev->dev, " R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(R_008020_GRBM_SOFT_RESET, tmp);
(void)RREG32(R_008020_GRBM_SOFT_RESET);
udelay(50);
WREG32(R_008020_GRBM_SOFT_RESET, 0);
(void)RREG32(R_008020_GRBM_SOFT_RESET);
}
/* Reset CP (we always reset CP) */
- WREG32(R_008020_GRBM_SOFT_RESET, S_008020_SOFT_RESET_CP(1));
+ tmp = S_008020_SOFT_RESET_CP(1);
+ dev_info(rdev->dev, "R_008020_GRBM_SOFT_RESET=0x%08X\n", tmp);
+ WREG32(R_008020_GRBM_SOFT_RESET, tmp);
(void)RREG32(R_008020_GRBM_SOFT_RESET);
udelay(50);
WREG32(R_008020_GRBM_SOFT_RESET, 0);
@@ -533,6 +540,14 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
srbm_reset |= S_000E60_SOFT_RESET_RLC(1);
if (G_000E50_SEM_BUSY(RREG32(R_000E50_SRBM_STATUS)))
srbm_reset |= S_000E60_SOFT_RESET_SEM(1);
+ if (G_000E50_BIF_BUSY(RREG32(R_000E50_SRBM_STATUS)))
+ srbm_reset |= S_000E60_SOFT_RESET_BIF(1);
+ dev_info(rdev->dev, " R_000E60_SRBM_SOFT_RESET=0x%08X\n", srbm_reset);
+ WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
+ (void)RREG32(R_000E60_SRBM_SOFT_RESET);
+ udelay(50);
+ WREG32(R_000E60_SRBM_SOFT_RESET, 0);
+ (void)RREG32(R_000E60_SRBM_SOFT_RESET);
WREG32(R_000E60_SRBM_SOFT_RESET, srbm_reset);
(void)RREG32(R_000E60_SRBM_SOFT_RESET);
udelay(50);
@@ -540,6 +555,17 @@ int r600_gpu_soft_reset(struct radeon_device *rdev)
(void)RREG32(R_000E60_SRBM_SOFT_RESET);
/* Wait a little for things to settle down */
udelay(50);
+ dev_info(rdev->dev, " R_008010_GRBM_STATUS=0x%08X\n",
+ RREG32(R_008010_GRBM_STATUS));
+ dev_info(rdev->dev, " R_008014_GRBM_STATUS2=0x%08X\n",
+ RREG32(R_008014_GRBM_STATUS2));
+ dev_info(rdev->dev, " R_000E50_SRBM_STATUS=0x%08X\n",
+ RREG32(R_000E50_SRBM_STATUS));
+ /* After reset we need to reinit the asic as GPU often endup in an
+ * incoherent state.
+ */
+ atom_asic_init(rdev->mode_info.atom_context);
+ rv515_mc_resume(rdev, &save);
return 0;
}
@@ -1350,32 +1376,47 @@ int r600_ring_test(struct radeon_device *rdev)
return r;
}
-/*
- * Writeback
- */
-int r600_wb_init(struct radeon_device *rdev)
+void r600_wb_disable(struct radeon_device *rdev)
+{
+ WREG32(SCRATCH_UMSK, 0);
+ if (rdev->wb.wb_obj) {
+ radeon_object_kunmap(rdev->wb.wb_obj);
+ radeon_object_unpin(rdev->wb.wb_obj);
+ }
+}
+
+void r600_wb_fini(struct radeon_device *rdev)
+{
+ r600_wb_disable(rdev);
+ if (rdev->wb.wb_obj) {
+ radeon_object_unref(&rdev->wb.wb_obj);
+ rdev->wb.wb = NULL;
+ rdev->wb.wb_obj = NULL;
+ }
+}
+
+int r600_wb_enable(struct radeon_device *rdev)
{
int r;
if (rdev->wb.wb_obj == NULL) {
- r = radeon_object_create(rdev, NULL, 4096,
- true,
- RADEON_GEM_DOMAIN_GTT,
- false, &rdev->wb.wb_obj);
+ r = radeon_object_create(rdev, NULL, 4096, true,
+ RADEON_GEM_DOMAIN_GTT, false, &rdev->wb.wb_obj);
if (r) {
- DRM_ERROR("radeon: failed to create WB buffer (%d).\n", r);
+ dev_warn(rdev->dev, "failed to create WB buffer (%d).\n", r);
return r;
}
- r = radeon_object_pin(rdev->wb.wb_obj,
- RADEON_GEM_DOMAIN_GTT,
- &rdev->wb.gpu_addr);
+ r = radeon_object_pin(rdev->wb.wb_obj, RADEON_GEM_DOMAIN_GTT,
+ &rdev->wb.gpu_addr);
if (r) {
- DRM_ERROR("radeon: failed to pin WB buffer (%d).\n", r);
+ dev_warn(rdev->dev, "failed to pin WB buffer (%d).\n", r);
+ r600_wb_fini(rdev);
return r;
}
r = radeon_object_kmap(rdev->wb.wb_obj, (void **)&rdev->wb.wb);
if (r) {
- DRM_ERROR("radeon: failed to map WB buffer (%d).\n", r);
+ dev_warn(rdev->dev, "failed to map WB buffer (%d).\n", r);
+ r600_wb_fini(rdev);
return r;
}
}
@@ -1386,21 +1427,6 @@ int r600_wb_init(struct radeon_device *rdev)
return 0;
}
-void r600_wb_fini(struct radeon_device *rdev)
-{
- if (rdev->wb.wb_obj) {
- radeon_object_kunmap(rdev->wb.wb_obj);
- radeon_object_unpin(rdev->wb.wb_obj);
- radeon_object_unref(&rdev->wb.wb_obj);
- rdev->wb.wb = NULL;
- rdev->wb.wb_obj = NULL;
- }
-}
-
-
-/*
- * CS
- */
void r600_fence_ring_emit(struct radeon_device *rdev,
struct radeon_fence *fence)
{
@@ -1477,11 +1503,14 @@ int r600_startup(struct radeon_device *rdev)
{
int r;
- r600_gpu_reset(rdev);
- r600_mc_resume(rdev);
- r = r600_pcie_gart_enable(rdev);
- if (r)
- return r;
+ r600_mc_program(rdev);
+ if (rdev->flags & RADEON_IS_AGP) {
+ r600_agp_enable(rdev);
+ } else {
+ r = r600_pcie_gart_enable(rdev);
+ if (r)
+ return r;
+ }
r600_gpu_init(rdev);
r = radeon_object_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
@@ -1500,9 +1529,8 @@ int r600_startup(struct radeon_device *rdev)
r = r600_cp_resume(rdev);
if (r)
return r;
- r = r600_wb_init(rdev);
- if (r)
- return r;
+ /* write back buffer are not vital so don't worry about failure */
+ r600_wb_enable(rdev);
return 0;
}
@@ -1524,15 +1552,12 @@ int r600_resume(struct radeon_device *rdev)
{
int r;
- if (radeon_gpu_reset(rdev)) {
- /* FIXME: what do we want to do here ? */
- }
+ /* Do not reset GPU before posting, on r600 hw unlike on r500 hw,
+ * posting will perform necessary task to bring back GPU into good
+ * shape.
+ */
/* post card */
- if (rdev->is_atom_bios) {
- atom_asic_init(rdev->mode_info.atom_context);
- } else {
- radeon_combios_asic_init(rdev->ddev);
- }
+ atom_asic_init(rdev->mode_info.atom_context);
/* Initialize clocks */
r = radeon_clocks_init(rdev);
if (r) {
@@ -1545,7 +1570,7 @@ int r600_resume(struct radeon_device *rdev)
return r;
}
- r = radeon_ib_test(rdev);
+ r = r600_ib_test(rdev);
if (r) {
DRM_ERROR("radeon: failled testing IB (%d).\n", r);
return r;
@@ -1553,13 +1578,12 @@ int r600_resume(struct radeon_device *rdev)
return r;
}
-
int r600_suspend(struct radeon_device *rdev)
{
/* FIXME: we should wait for ring to be empty */
r600_cp_stop(rdev);
rdev->cp.ready = false;
-
+ r600_wb_disable(rdev);
r600_pcie_gart_disable(rdev);
/* unpin shaders bo */
radeon_object_unpin(rdev->r600_blit.shader_obj);
@@ -1576,7 +1600,6 @@ int r600_init(struct radeon_device *rdev)
{
int r;
- rdev->new_init_path = true;
r = radeon_dummy_page_init(rdev);
if (r)
return r;
@@ -1593,8 +1616,10 @@ int r600_init(struct radeon_device *rdev)
return -EINVAL;
}
/* Must be an ATOMBIOS */
- if (!rdev->is_atom_bios)
+ if (!rdev->is_atom_bios) {
+ dev_err(rdev->dev, "Expecting atombios for R600 GPU\n");
return -EINVAL;
+ }
r = radeon_atombios_init(rdev);
if (r)
return r;
@@ -1616,15 +1641,8 @@ int r600_init(struct radeon_device *rdev)
if (r)
return r;
r = r600_mc_init(rdev);
- if (r) {
- if (rdev->flags & RADEON_IS_AGP) {
- /* Retry with disabling AGP */
- r600_fini(rdev);
- rdev->flags &= ~RADEON_IS_AGP;
- return r600_init(rdev);
- }
+ if (r)
return r;
- }
/* Memory manager */
r = radeon_object_init(rdev);
if (r)
@@ -1653,12 +1671,10 @@ int r600_init(struct radeon_device *rdev)
r = r600_startup(rdev);
if (r) {
- if (rdev->flags & RADEON_IS_AGP) {
- /* Retry with disabling AGP */
- r600_fini(rdev);
- rdev->flags &= ~RADEON_IS_AGP;
- return r600_init(rdev);
- }
+ r600_suspend(rdev);
+ r600_wb_fini(rdev);
+ radeon_ring_fini(rdev);
+ r600_pcie_gart_fini(rdev);
rdev->accel_working = false;
}
if (rdev->accel_working) {
@@ -1667,7 +1683,7 @@ int r600_init(struct radeon_device *rdev)
DRM_ERROR("radeon: failled initializing IB pool (%d).\n", r);
rdev->accel_working = false;
}
- r = radeon_ib_test(rdev);
+ r = r600_ib_test(rdev);
if (r) {
DRM_ERROR("radeon: failled testing IB (%d).\n", r);
rdev->accel_working = false;
@@ -1683,19 +1699,15 @@ void r600_fini(struct radeon_device *rdev)
r600_blit_fini(rdev);
radeon_ring_fini(rdev);
+ r600_wb_fini(rdev);
r600_pcie_gart_fini(rdev);
radeon_gem_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_clocks_fini(rdev);
-#if __OS_HAS_AGP
if (rdev->flags & RADEON_IS_AGP)
radeon_agp_fini(rdev);
-#endif
radeon_object_fini(rdev);
- if (rdev->is_atom_bios)
- radeon_atombios_fini(rdev);
- else
- radeon_combios_fini(rdev);
+ radeon_atombios_fini(rdev);
kfree(rdev->bios);
rdev->bios = NULL;
radeon_dummy_page_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c
index d28970db6a2d..17e42195c632 100644
--- a/drivers/gpu/drm/radeon/r600_cs.c
+++ b/drivers/gpu/drm/radeon/r600_cs.c
@@ -252,7 +252,7 @@ static int r600_cs_packet_parse_vline(struct radeon_cs_parser *p)
header = radeon_get_ib_value(p, h_idx);
crtc_id = radeon_get_ib_value(p, h_idx + 2 + 7 + 1);
- reg = header >> 2;
+ reg = CP_PACKET0_GET_REG(header);
mutex_lock(&p->rdev->ddev->mode_config.mutex);
obj = drm_mode_object_find(p->rdev->ddev, crtc_id, DRM_MODE_OBJECT_CRTC);
if (!obj) {
diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h
index 4a9028a85c9b..9b64d47f1f82 100644
--- a/drivers/gpu/drm/radeon/r600d.h
+++ b/drivers/gpu/drm/radeon/r600d.h
@@ -643,6 +643,7 @@
#define G_000E50_MCDW_BUSY(x) (((x) >> 13) & 1)
#define G_000E50_SEM_BUSY(x) (((x) >> 14) & 1)
#define G_000E50_RLC_BUSY(x) (((x) >> 15) & 1)
+#define G_000E50_BIF_BUSY(x) (((x) >> 29) & 1)
#define R_000E60_SRBM_SOFT_RESET 0x0E60
#define S_000E60_SOFT_RESET_BIF(x) (((x) & 1) << 1)
#define S_000E60_SOFT_RESET_CG(x) (((x) & 1) << 2)
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 950b346e343f..5ab35b81c86b 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -590,18 +590,8 @@ struct radeon_asic {
void (*fini)(struct radeon_device *rdev);
int (*resume)(struct radeon_device *rdev);
int (*suspend)(struct radeon_device *rdev);
- void (*errata)(struct radeon_device *rdev);
- void (*vram_info)(struct radeon_device *rdev);
void (*vga_set_state)(struct radeon_device *rdev, bool state);
int (*gpu_reset)(struct radeon_device *rdev);
- int (*mc_init)(struct radeon_device *rdev);
- void (*mc_fini)(struct radeon_device *rdev);
- int (*wb_init)(struct radeon_device *rdev);
- void (*wb_fini)(struct radeon_device *rdev);
- int (*gart_init)(struct radeon_device *rdev);
- void (*gart_fini)(struct radeon_device *rdev);
- int (*gart_enable)(struct radeon_device *rdev);
- void (*gart_disable)(struct radeon_device *rdev);
void (*gart_tlb_flush)(struct radeon_device *rdev);
int (*gart_set_page)(struct radeon_device *rdev, int i, uint64_t addr);
int (*cp_init)(struct radeon_device *rdev, unsigned ring_size);
@@ -611,7 +601,6 @@ struct radeon_asic {
void (*ring_start)(struct radeon_device *rdev);
int (*ring_test)(struct radeon_device *rdev);
void (*ring_ib_execute)(struct radeon_device *rdev, struct radeon_ib *ib);
- int (*ib_test)(struct radeon_device *rdev);
int (*irq_set)(struct radeon_device *rdev);
int (*irq_process)(struct radeon_device *rdev);
u32 (*get_vblank_counter)(struct radeon_device *rdev, int crtc);
@@ -789,7 +778,6 @@ struct radeon_device {
bool shutdown;
bool suspend;
bool need_dma32;
- bool new_init_path;
bool accel_working;
struct radeon_surface_reg surface_regs[RADEON_GEM_MAX_SURFACES];
const struct firmware *me_fw; /* all family ME firmware */
@@ -949,28 +937,14 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v)
#define radeon_resume(rdev) (rdev)->asic->resume((rdev))
#define radeon_suspend(rdev) (rdev)->asic->suspend((rdev))
#define radeon_cs_parse(p) rdev->asic->cs_parse((p))
-#define radeon_errata(rdev) (rdev)->asic->errata((rdev))
-#define radeon_vram_info(rdev) (rdev)->asic->vram_info((rdev))
#define radeon_vga_set_state(rdev, state) (rdev)->asic->vga_set_state((rdev), (state))
#define radeon_gpu_reset(rdev) (rdev)->asic->gpu_reset((rdev))
-#define radeon_mc_init(rdev) (rdev)->asic->mc_init((rdev))
-#define radeon_mc_fini(rdev) (rdev)->asic->mc_fini((rdev))
-#define radeon_wb_init(rdev) (rdev)->asic->wb_init((rdev))
-#define radeon_wb_fini(rdev) (rdev)->asic->wb_fini((rdev))
-#define radeon_gpu_gart_init(rdev) (rdev)->asic->gart_init((rdev))
-#define radeon_gpu_gart_fini(rdev) (rdev)->asic->gart_fini((rdev))
-#define radeon_gart_enable(rdev) (rdev)->asic->gart_enable((rdev))
-#define radeon_gart_disable(rdev) (rdev)->asic->gart_disable((rdev))
#define radeon_gart_tlb_flush(rdev) (rdev)->asic->gart_tlb_flush((rdev))
#define radeon_gart_set_page(rdev, i, p) (rdev)->asic->gart_set_page((rdev), (i), (p))
-#define radeon_cp_init(rdev,rsize) (rdev)->asic->cp_init((rdev), (rsize))
-#define radeon_cp_fini(rdev) (rdev)->asic->cp_fini((rdev))
-#define radeon_cp_disable(rdev) (rdev)->asic->cp_disable((rdev))
#define radeon_cp_commit(rdev) (rdev)->asic->cp_commit((rdev))
#define radeon_ring_start(rdev) (rdev)->asic->ring_start((rdev))
#define radeon_ring_test(rdev) (rdev)->asic->ring_test((rdev))
#define radeon_ring_ib_execute(rdev, ib) (rdev)->asic->ring_ib_execute((rdev), (ib))
-#define radeon_ib_test(rdev) (rdev)->asic->ib_test((rdev))
#define radeon_irq_set(rdev) (rdev)->asic->irq_set((rdev))
#define radeon_irq_process(rdev) (rdev)->asic->irq_process((rdev))
#define radeon_get_vblank_counter(rdev, crtc) (rdev)->asic->get_vblank_counter((rdev), (crtc))
@@ -996,6 +970,7 @@ extern void radeon_clocks_fini(struct radeon_device *rdev);
extern void radeon_scratch_init(struct radeon_device *rdev);
extern void radeon_surface_init(struct radeon_device *rdev);
extern int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data);
+extern void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable);
extern void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
/* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */
@@ -1031,11 +1006,27 @@ extern int r100_wb_init(struct radeon_device *rdev);
extern void r100_hdp_reset(struct radeon_device *rdev);
extern int r100_rb2d_reset(struct radeon_device *rdev);
extern int r100_cp_reset(struct radeon_device *rdev);
+extern void r100_vga_render_disable(struct radeon_device *rdev);
+extern int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p,
+ struct radeon_cs_packet *pkt,
+ struct radeon_object *robj);
+extern int r100_cs_parse_packet0(struct radeon_cs_parser *p,
+ struct radeon_cs_packet *pkt,
+ const unsigned *auth, unsigned n,
+ radeon_packet0_check_t check);
+extern int r100_cs_packet_parse(struct radeon_cs_parser *p,
+ struct radeon_cs_packet *pkt,
+ unsigned idx);
+
+/* rv200,rv250,rv280 */
+extern void r200_set_safe_registers(struct radeon_device *rdev);
/* r300,r350,rv350,rv370,rv380 */
extern void r300_set_reg_safe(struct radeon_device *rdev);
extern void r300_mc_program(struct radeon_device *rdev);
extern void r300_vram_info(struct radeon_device *rdev);
+extern void r300_clock_startup(struct radeon_device *rdev);
+extern int r300_mc_wait_for_idle(struct radeon_device *rdev);
extern int rv370_pcie_gart_init(struct radeon_device *rdev);
extern void rv370_pcie_gart_fini(struct radeon_device *rdev);
extern int rv370_pcie_gart_enable(struct radeon_device *rdev);
@@ -1066,6 +1057,18 @@ extern void rv515_clock_startup(struct radeon_device *rdev);
extern void rv515_debugfs(struct radeon_device *rdev);
extern int rv515_suspend(struct radeon_device *rdev);
+/* rs400 */
+extern int rs400_gart_init(struct radeon_device *rdev);
+extern int rs400_gart_enable(struct radeon_device *rdev);
+extern void rs400_gart_adjust_size(struct radeon_device *rdev);
+extern void rs400_gart_disable(struct radeon_device *rdev);
+extern void rs400_gart_fini(struct radeon_device *rdev);
+
+/* rs600 */
+extern void rs600_set_safe_registers(struct radeon_device *rdev);
+extern int rs600_irq_set(struct radeon_device *rdev);
+extern void rs600_irq_disable(struct radeon_device *rdev);
+
/* rs690, rs740 */
extern void rs690_line_buffer_adjust(struct radeon_device *rdev,
struct drm_display_mode *mode1,
@@ -1083,8 +1086,9 @@ extern int r600_pcie_gart_init(struct radeon_device *rdev);
extern void r600_pcie_gart_tlb_flush(struct radeon_device *rdev);
extern int r600_ib_test(struct radeon_device *rdev);
extern int r600_ring_test(struct radeon_device *rdev);
-extern int r600_wb_init(struct radeon_device *rdev);
extern void r600_wb_fini(struct radeon_device *rdev);
+extern int r600_wb_enable(struct radeon_device *rdev);
+extern void r600_wb_disable(struct radeon_device *rdev);
extern void r600_scratch_init(struct radeon_device *rdev);
extern int r600_blit_init(struct radeon_device *rdev);
extern void r600_blit_fini(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index c8a4e7b5663d..c3532c7a6f3f 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -41,28 +41,17 @@ void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable);
/*
* r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280
*/
-int r100_init(struct radeon_device *rdev);
-int r200_init(struct radeon_device *rdev);
+extern int r100_init(struct radeon_device *rdev);
+extern void r100_fini(struct radeon_device *rdev);
+extern int r100_suspend(struct radeon_device *rdev);
+extern int r100_resume(struct radeon_device *rdev);
uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg);
void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
-void r100_errata(struct radeon_device *rdev);
-void r100_vram_info(struct radeon_device *rdev);
void r100_vga_set_state(struct radeon_device *rdev, bool state);
int r100_gpu_reset(struct radeon_device *rdev);
-int r100_mc_init(struct radeon_device *rdev);
-void r100_mc_fini(struct radeon_device *rdev);
u32 r100_get_vblank_counter(struct radeon_device *rdev, int crtc);
-int r100_wb_init(struct radeon_device *rdev);
-void r100_wb_fini(struct radeon_device *rdev);
-int r100_pci_gart_init(struct radeon_device *rdev);
-void r100_pci_gart_fini(struct radeon_device *rdev);
-int r100_pci_gart_enable(struct radeon_device *rdev);
-void r100_pci_gart_disable(struct radeon_device *rdev);
void r100_pci_gart_tlb_flush(struct radeon_device *rdev);
int r100_pci_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
-int r100_cp_init(struct radeon_device *rdev, unsigned ring_size);
-void r100_cp_fini(struct radeon_device *rdev);
-void r100_cp_disable(struct radeon_device *rdev);
void r100_cp_commit(struct radeon_device *rdev);
void r100_ring_start(struct radeon_device *rdev);
int r100_irq_set(struct radeon_device *rdev);
@@ -83,33 +72,21 @@ int r100_set_surface_reg(struct radeon_device *rdev, int reg,
int r100_clear_surface_reg(struct radeon_device *rdev, int reg);
void r100_bandwidth_update(struct radeon_device *rdev);
void r100_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
-int r100_ib_test(struct radeon_device *rdev);
int r100_ring_test(struct radeon_device *rdev);
static struct radeon_asic r100_asic = {
.init = &r100_init,
- .errata = &r100_errata,
- .vram_info = &r100_vram_info,
+ .fini = &r100_fini,
+ .suspend = &r100_suspend,
+ .resume = &r100_resume,
.vga_set_state = &r100_vga_set_state,
.gpu_reset = &r100_gpu_reset,
- .mc_init = &r100_mc_init,
- .mc_fini = &r100_mc_fini,
- .wb_init = &r100_wb_init,
- .wb_fini = &r100_wb_fini,
- .gart_init = &r100_pci_gart_init,
- .gart_fini = &r100_pci_gart_fini,
- .gart_enable = &r100_pci_gart_enable,
- .gart_disable = &r100_pci_gart_disable,
.gart_tlb_flush = &r100_pci_gart_tlb_flush,
.gart_set_page = &r100_pci_gart_set_page,
- .cp_init = &r100_cp_init,
- .cp_fini = &r100_cp_fini,
- .cp_disable = &r100_cp_disable,
.cp_commit = &r100_cp_commit,
.ring_start = &r100_ring_start,
.ring_test = &r100_ring_test,
.ring_ib_execute = &r100_ring_ib_execute,
- .ib_test = &r100_ib_test,
.irq_set = &r100_irq_set,
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
@@ -131,55 +108,38 @@ static struct radeon_asic r100_asic = {
/*
* r300,r350,rv350,rv380
*/
-int r300_init(struct radeon_device *rdev);
-void r300_errata(struct radeon_device *rdev);
-void r300_vram_info(struct radeon_device *rdev);
-int r300_gpu_reset(struct radeon_device *rdev);
-int r300_mc_init(struct radeon_device *rdev);
-void r300_mc_fini(struct radeon_device *rdev);
-void r300_ring_start(struct radeon_device *rdev);
-void r300_fence_ring_emit(struct radeon_device *rdev,
- struct radeon_fence *fence);
-int r300_cs_parse(struct radeon_cs_parser *p);
-int rv370_pcie_gart_init(struct radeon_device *rdev);
-void rv370_pcie_gart_fini(struct radeon_device *rdev);
-int rv370_pcie_gart_enable(struct radeon_device *rdev);
-void rv370_pcie_gart_disable(struct radeon_device *rdev);
-void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev);
-int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
-uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg);
-void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
-void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes);
-int r300_copy_dma(struct radeon_device *rdev,
- uint64_t src_offset,
- uint64_t dst_offset,
- unsigned num_pages,
- struct radeon_fence *fence);
-
+extern int r300_init(struct radeon_device *rdev);
+extern void r300_fini(struct radeon_device *rdev);
+extern int r300_suspend(struct radeon_device *rdev);
+extern int r300_resume(struct radeon_device *rdev);
+extern int r300_gpu_reset(struct radeon_device *rdev);
+extern void r300_ring_start(struct radeon_device *rdev);
+extern void r300_fence_ring_emit(struct radeon_device *rdev,
+ struct radeon_fence *fence);
+extern int r300_cs_parse(struct radeon_cs_parser *p);
+extern void rv370_pcie_gart_tlb_flush(struct radeon_device *rdev);
+extern int rv370_pcie_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
+extern uint32_t rv370_pcie_rreg(struct radeon_device *rdev, uint32_t reg);
+extern void rv370_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
+extern void rv370_set_pcie_lanes(struct radeon_device *rdev, int lanes);
+extern int r300_copy_dma(struct radeon_device *rdev,
+ uint64_t src_offset,
+ uint64_t dst_offset,
+ unsigned num_pages,
+ struct radeon_fence *fence);
static struct radeon_asic r300_asic = {
.init = &r300_init,
- .errata = &r300_errata,
- .vram_info = &r300_vram_info,
+ .fini = &r300_fini,
+ .suspend = &r300_suspend,
+ .resume = &r300_resume,
.vga_set_state = &r100_vga_set_state,
.gpu_reset = &r300_gpu_reset,
- .mc_init = &r300_mc_init,
- .mc_fini = &r300_mc_fini,
- .wb_init = &r100_wb_init,
- .wb_fini = &r100_wb_fini,
- .gart_init = &r100_pci_gart_init,
- .gart_fini = &r100_pci_gart_fini,
- .gart_enable = &r100_pci_gart_enable,
- .gart_disable = &r100_pci_gart_disable,
.gart_tlb_flush = &r100_pci_gart_tlb_flush,
.gart_set_page = &r100_pci_gart_set_page,
- .cp_init = &r100_cp_init,
- .cp_fini = &r100_cp_fini,
- .cp_disable = &r100_cp_disable,
.cp_commit = &r100_cp_commit,
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ring_ib_execute = &r100_ring_ib_execute,
- .ib_test = &r100_ib_test,
.irq_set = &r100_irq_set,
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
@@ -209,26 +169,14 @@ static struct radeon_asic r420_asic = {
.fini = &r420_fini,
.suspend = &r420_suspend,
.resume = &r420_resume,
- .errata = NULL,
- .vram_info = NULL,
.vga_set_state = &r100_vga_set_state,
.gpu_reset = &r300_gpu_reset,
- .mc_init = NULL,
- .mc_fini = NULL,
- .wb_init = NULL,
- .wb_fini = NULL,
- .gart_enable = NULL,
- .gart_disable = NULL,
.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
.gart_set_page = &rv370_pcie_gart_set_page,
- .cp_init = NULL,
- .cp_fini = NULL,
- .cp_disable = NULL,
.cp_commit = &r100_cp_commit,
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ring_ib_execute = &r100_ring_ib_execute,
- .ib_test = NULL,
.irq_set = &r100_irq_set,
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
@@ -250,42 +198,27 @@ static struct radeon_asic r420_asic = {
/*
* rs400,rs480
*/
-void rs400_errata(struct radeon_device *rdev);
-void rs400_vram_info(struct radeon_device *rdev);
-int rs400_mc_init(struct radeon_device *rdev);
-void rs400_mc_fini(struct radeon_device *rdev);
-int rs400_gart_init(struct radeon_device *rdev);
-void rs400_gart_fini(struct radeon_device *rdev);
-int rs400_gart_enable(struct radeon_device *rdev);
-void rs400_gart_disable(struct radeon_device *rdev);
+extern int rs400_init(struct radeon_device *rdev);
+extern void rs400_fini(struct radeon_device *rdev);
+extern int rs400_suspend(struct radeon_device *rdev);
+extern int rs400_resume(struct radeon_device *rdev);
void rs400_gart_tlb_flush(struct radeon_device *rdev);
int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg);
void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
static struct radeon_asic rs400_asic = {
- .init = &r300_init,
- .errata = &rs400_errata,
- .vram_info = &rs400_vram_info,
+ .init = &rs400_init,
+ .fini = &rs400_fini,
+ .suspend = &rs400_suspend,
+ .resume = &rs400_resume,
.vga_set_state = &r100_vga_set_state,
.gpu_reset = &r300_gpu_reset,
- .mc_init = &rs400_mc_init,
- .mc_fini = &rs400_mc_fini,
- .wb_init = &r100_wb_init,
- .wb_fini = &r100_wb_fini,
- .gart_init = &rs400_gart_init,
- .gart_fini = &rs400_gart_fini,
- .gart_enable = &rs400_gart_enable,
- .gart_disable = &rs400_gart_disable,
.gart_tlb_flush = &rs400_gart_tlb_flush,
.gart_set_page = &rs400_gart_set_page,
- .cp_init = &r100_cp_init,
- .cp_fini = &r100_cp_fini,
- .cp_disable = &r100_cp_disable,
.cp_commit = &r100_cp_commit,
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ring_ib_execute = &r100_ring_ib_execute,
- .ib_test = &r100_ib_test,
.irq_set = &r100_irq_set,
.irq_process = &r100_irq_process,
.get_vblank_counter = &r100_get_vblank_counter,
@@ -307,18 +240,13 @@ static struct radeon_asic rs400_asic = {
/*
* rs600.
*/
-int rs600_init(struct radeon_device *rdev);
-void rs600_errata(struct radeon_device *rdev);
-void rs600_vram_info(struct radeon_device *rdev);
-int rs600_mc_init(struct radeon_device *rdev);
-void rs600_mc_fini(struct radeon_device *rdev);
+extern int rs600_init(struct radeon_device *rdev);
+extern void rs600_fini(struct radeon_device *rdev);
+extern int rs600_suspend(struct radeon_device *rdev);
+extern int rs600_resume(struct radeon_device *rdev);
int rs600_irq_set(struct radeon_device *rdev);
int rs600_irq_process(struct radeon_device *rdev);
u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc);
-int rs600_gart_init(struct radeon_device *rdev);
-void rs600_gart_fini(struct radeon_device *rdev);
-int rs600_gart_enable(struct radeon_device *rdev);
-void rs600_gart_disable(struct radeon_device *rdev);
void rs600_gart_tlb_flush(struct radeon_device *rdev);
int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr);
uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg);
@@ -326,28 +254,17 @@ void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
void rs600_bandwidth_update(struct radeon_device *rdev);
static struct radeon_asic rs600_asic = {
.init = &rs600_init,
- .errata = &rs600_errata,
- .vram_info = &rs600_vram_info,
+ .fini = &rs600_fini,
+ .suspend = &rs600_suspend,
+ .resume = &rs600_resume,
.vga_set_state = &r100_vga_set_state,
.gpu_reset = &r300_gpu_reset,
- .mc_init = &rs600_mc_init,
- .mc_fini = &rs600_mc_fini,
- .wb_init = &r100_wb_init,
- .wb_fini = &r100_wb_fini,
- .gart_init = &rs600_gart_init,
- .gart_fini = &rs600_gart_fini,
- .gart_enable = &rs600_gart_enable,
- .gart_disable = &rs600_gart_disable,
.gart_tlb_flush = &rs600_gart_tlb_flush,
.gart_set_page = &rs600_gart_set_page,
- .cp_init = &r100_cp_init,
- .cp_fini = &r100_cp_fini,
- .cp_disable = &r100_cp_disable,
.cp_commit = &r100_cp_commit,
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ring_ib_execute = &r100_ring_ib_execute,
- .ib_test = &r100_ib_test,
.irq_set = &rs600_irq_set,
.irq_process = &rs600_irq_process,
.get_vblank_counter = &rs600_get_vblank_counter,
@@ -367,37 +284,26 @@ static struct radeon_asic rs600_asic = {
/*
* rs690,rs740
*/
-void rs690_errata(struct radeon_device *rdev);
-void rs690_vram_info(struct radeon_device *rdev);
-int rs690_mc_init(struct radeon_device *rdev);
-void rs690_mc_fini(struct radeon_device *rdev);
+int rs690_init(struct radeon_device *rdev);
+void rs690_fini(struct radeon_device *rdev);
+int rs690_resume(struct radeon_device *rdev);
+int rs690_suspend(struct radeon_device *rdev);
uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg);
void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
void rs690_bandwidth_update(struct radeon_device *rdev);
static struct radeon_asic rs690_asic = {
- .init = &rs600_init,
- .errata = &rs690_errata,
- .vram_info = &rs690_vram_info,
+ .init = &rs690_init,
+ .fini = &rs690_fini,
+ .suspend = &rs690_suspend,
+ .resume = &rs690_resume,
.vga_set_state = &r100_vga_set_state,
.gpu_reset = &r300_gpu_reset,
- .mc_init = &rs690_mc_init,
- .mc_fini = &rs690_mc_fini,
- .wb_init = &r100_wb_init,
- .wb_fini = &r100_wb_fini,
- .gart_init = &rs400_gart_init,
- .gart_fini = &rs400_gart_fini,
- .gart_enable = &rs400_gart_enable,
- .gart_disable = &rs400_gart_disable,
.gart_tlb_flush = &rs400_gart_tlb_flush,
.gart_set_page = &rs400_gart_set_page,
- .cp_init = &r100_cp_init,
- .cp_fini = &r100_cp_fini,
- .cp_disable = &r100_cp_disable,
.cp_commit = &r100_cp_commit,
.ring_start = &r300_ring_start,
.ring_test = &r100_ring_test,
.ring_ib_execute = &r100_ring_ib_execute,
- .ib_test = &r100_ib_test,
.irq_set = &rs600_irq_set,
.irq_process = &rs600_irq_process,
.get_vblank_counter = &rs600_get_vblank_counter,
@@ -435,28 +341,14 @@ static struct radeon_asic rv515_asic = {
.fini = &rv515_fini,
.suspend = &rv515_suspend,
.resume = &rv515_resume,
- .errata = NULL,
- .vram_info = NULL,
.vga_set_state = &r100_vga_set_state,
.gpu_reset = &rv515_gpu_reset,
- .mc_init = NULL,
- .mc_fini = NULL,
- .wb_init = NULL,
- .wb_fini = NULL,
- .gart_init = &rv370_pcie_gart_init,
- .gart_fini = &rv370_pcie_gart_fini,
- .gart_enable = NULL,
- .gart_disable = NULL,
.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
.gart_set_page = &rv370_pcie_gart_set_page,
- .cp_init = NULL,
- .cp_fini = NULL,
- .cp_disable = NULL,
.cp_commit = &r100_cp_commit,
.ring_start = &rv515_ring_start,
.ring_test = &r100_ring_test,
.ring_ib_execute = &r100_ring_ib_execute,
- .ib_test = NULL,
.irq_set = &rs600_irq_set,
.irq_process = &rs600_irq_process,
.get_vblank_counter = &rs600_get_vblank_counter,
@@ -485,28 +377,14 @@ static struct radeon_asic r520_asic = {
.fini = &rv515_fini,
.suspend = &rv515_suspend,
.resume = &r520_resume,
- .errata = NULL,
- .vram_info = NULL,
.vga_set_state = &r100_vga_set_state,
.gpu_reset = &rv515_gpu_reset,
- .mc_init = NULL,
- .mc_fini = NULL,
- .wb_init = NULL,
- .wb_fini = NULL,
- .gart_init = NULL,
- .gart_fini = NULL,
- .gart_enable = NULL,
- .gart_disable = NULL,
.gart_tlb_flush = &rv370_pcie_gart_tlb_flush,
.gart_set_page = &rv370_pcie_gart_set_page,
- .cp_init = NULL,
- .cp_fini = NULL,
- .cp_disable = NULL,
.cp_commit = &r100_cp_commit,
.ring_start = &rv515_ring_start,
.ring_test = &r100_ring_test,
.ring_ib_execute = &r100_ring_ib_execute,
- .ib_test = NULL,
.irq_set = &rs600_irq_set,
.irq_process = &rs600_irq_process,
.get_vblank_counter = &rs600_get_vblank_counter,
@@ -554,37 +432,23 @@ int r600_set_surface_reg(struct radeon_device *rdev, int reg,
uint32_t offset, uint32_t obj_size);
int r600_clear_surface_reg(struct radeon_device *rdev, int reg);
void r600_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
-int r600_ib_test(struct radeon_device *rdev);
int r600_ring_test(struct radeon_device *rdev);
int r600_copy_blit(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_pages, struct radeon_fence *fence);
static struct radeon_asic r600_asic = {
- .errata = NULL,
.init = &r600_init,
.fini = &r600_fini,
.suspend = &r600_suspend,
.resume = &r600_resume,
.cp_commit = &r600_cp_commit,
- .vram_info = NULL,
.vga_set_state = &r600_vga_set_state,
.gpu_reset = &r600_gpu_reset,
- .mc_init = NULL,
- .mc_fini = NULL,
- .wb_init = &r600_wb_init,
- .wb_fini = &r600_wb_fini,
- .gart_enable = NULL,
- .gart_disable = NULL,
.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
.gart_set_page = &rs600_gart_set_page,
- .cp_init = NULL,
- .cp_fini = NULL,
- .cp_disable = NULL,
- .ring_start = NULL,
.ring_test = &r600_ring_test,
.ring_ib_execute = &r600_ring_ib_execute,
- .ib_test = &r600_ib_test,
.irq_set = &r600_irq_set,
.irq_process = &r600_irq_process,
.fence_ring_emit = &r600_fence_ring_emit,
@@ -611,30 +475,17 @@ int rv770_resume(struct radeon_device *rdev);
int rv770_gpu_reset(struct radeon_device *rdev);
static struct radeon_asic rv770_asic = {
- .errata = NULL,
.init = &rv770_init,
.fini = &rv770_fini,
.suspend = &rv770_suspend,
.resume = &rv770_resume,
.cp_commit = &r600_cp_commit,
- .vram_info = NULL,
.gpu_reset = &rv770_gpu_reset,
.vga_set_state = &r600_vga_set_state,
- .mc_init = NULL,
- .mc_fini = NULL,
- .wb_init = &r600_wb_init,
- .wb_fini = &r600_wb_fini,
- .gart_enable = NULL,
- .gart_disable = NULL,
.gart_tlb_flush = &r600_pcie_gart_tlb_flush,
.gart_set_page = &rs600_gart_set_page,
- .cp_init = NULL,
- .cp_fini = NULL,
- .cp_disable = NULL,
- .ring_start = NULL,
.ring_test = &r600_ring_test,
.ring_ib_execute = &r600_ring_ib_execute,
- .ib_test = &r600_ib_test,
.irq_set = &r600_irq_set,
.irq_process = &r600_irq_process,
.fence_ring_emit = &r600_fence_ring_emit,
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index 5b6c08cee40e..79d4b771c770 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -798,27 +798,29 @@ 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);
encoder->native_mode = lvds->native_mode;
}
@@ -857,8 +859,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 +867,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 +877,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 +916,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_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c
index 96e37a6e7ce4..34a9b9119518 100644
--- a/drivers/gpu/drm/radeon/radeon_bios.c
+++ b/drivers/gpu/drm/radeon/radeon_bios.c
@@ -33,12 +33,50 @@
/*
* BIOS.
*/
+
+/* If you boot an IGP board with a discrete card as the primary,
+ * the IGP rom is not accessible via the rom bar as the IGP rom is
+ * part of the system bios. On boot, the system bios puts a
+ * copy of the igp rom at the start of vram if a discrete card is
+ * present.
+ */
+static bool igp_read_bios_from_vram(struct radeon_device *rdev)
+{
+ uint8_t __iomem *bios;
+ resource_size_t vram_base;
+ resource_size_t size = 256 * 1024; /* ??? */
+
+ rdev->bios = NULL;
+ vram_base = drm_get_resource_start(rdev->ddev, 0);
+ bios = ioremap(vram_base, size);
+ if (!bios) {
+ DRM_ERROR("Unable to mmap vram\n");
+ return false;
+ }
+
+ if (size == 0 || bios[0] != 0x55 || bios[1] != 0xaa) {
+ iounmap(bios);
+ DRM_ERROR("bad rom signature\n");
+ return false;
+ }
+ rdev->bios = kmalloc(size, GFP_KERNEL);
+ if (rdev->bios == NULL) {
+ iounmap(bios);
+ DRM_ERROR("kmalloc failed\n");
+ return false;
+ }
+ memcpy(rdev->bios, bios, size);
+ iounmap(bios);
+ return true;
+}
+
static bool radeon_read_bios(struct radeon_device *rdev)
{
uint8_t __iomem *bios;
size_t size;
rdev->bios = NULL;
+ /* XXX: some cards may return 0 for rom size? ddx has a workaround */
bios = pci_map_rom(rdev->pdev, &size);
if (!bios) {
return false;
@@ -341,7 +379,9 @@ static bool legacy_read_disabled_bios(struct radeon_device *rdev)
static bool radeon_read_disabled_bios(struct radeon_device *rdev)
{
- if (rdev->family >= CHIP_RV770)
+ if (rdev->flags & RADEON_IS_IGP)
+ return igp_read_bios_from_vram(rdev);
+ else if (rdev->family >= CHIP_RV770)
return r700_read_disabled_bios(rdev);
else if (rdev->family >= CHIP_R600)
return r600_read_disabled_bios(rdev);
@@ -356,7 +396,12 @@ bool radeon_get_bios(struct radeon_device *rdev)
bool r;
uint16_t tmp;
- r = radeon_read_bios(rdev);
+ if (rdev->flags & RADEON_IS_IGP) {
+ r = igp_read_bios_from_vram(rdev);
+ if (r == false)
+ r = radeon_read_bios(rdev);
+ } else
+ r = radeon_read_bios(rdev);
if (r == false) {
r = radeon_read_disabled_bios(rdev);
}
diff --git a/drivers/gpu/drm/radeon/radeon_clocks.c b/drivers/gpu/drm/radeon/radeon_clocks.c
index 152eef13197a..f5c32a766b10 100644
--- a/drivers/gpu/drm/radeon/radeon_clocks.c
+++ b/drivers/gpu/drm/radeon/radeon_clocks.c
@@ -411,7 +411,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable)
R300_PIXCLK_TRANS_ALWAYS_ONb |
R300_PIXCLK_TVO_ALWAYS_ONb |
R300_P2G2CLK_ALWAYS_ONb |
- R300_P2G2CLK_ALWAYS_ONb);
+ R300_P2G2CLK_DAC_ALWAYS_ONb);
WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
} else if (rdev->family >= CHIP_RV350) {
tmp = RREG32_PLL(R300_SCLK_CNTL2);
@@ -464,7 +464,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable)
R300_PIXCLK_TRANS_ALWAYS_ONb |
R300_PIXCLK_TVO_ALWAYS_ONb |
R300_P2G2CLK_ALWAYS_ONb |
- R300_P2G2CLK_ALWAYS_ONb);
+ R300_P2G2CLK_DAC_ALWAYS_ONb);
WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
tmp = RREG32_PLL(RADEON_MCLK_MISC);
@@ -654,7 +654,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable)
R300_PIXCLK_TRANS_ALWAYS_ONb |
R300_PIXCLK_TVO_ALWAYS_ONb |
R300_P2G2CLK_ALWAYS_ONb |
- R300_P2G2CLK_ALWAYS_ONb |
+ R300_P2G2CLK_DAC_ALWAYS_ONb |
R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF);
WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
} else if (rdev->family >= CHIP_RV350) {
@@ -705,7 +705,7 @@ void radeon_legacy_set_clock_gating(struct radeon_device *rdev, int enable)
R300_PIXCLK_TRANS_ALWAYS_ONb |
R300_PIXCLK_TVO_ALWAYS_ONb |
R300_P2G2CLK_ALWAYS_ONb |
- R300_P2G2CLK_ALWAYS_ONb |
+ R300_P2G2CLK_DAC_ALWAYS_ONb |
R300_DISP_DAC_PIXCLK_DAC2_BLANK_OFF);
WREG32_PLL(RADEON_PIXCLKS_CNTL, tmp);
} else {
diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c
index 748265a105b3..e91aba8530b6 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 {
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index e376be47a4a0..729207a1e83e 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;
@@ -237,10 +224,10 @@ 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_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 +331,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 +397,31 @@ 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;
+ bool dret;
+
+ 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->ddc_bus) {
+ 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;
+ }
/* check acpi lid status ??? */
+
radeon_connector_update_scratch_regs(connector, ret);
return ret;
}
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index ec835d56d30a..3d667031de6e 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -322,10 +322,6 @@ int radeon_asic_init(struct radeon_device *rdev)
case CHIP_RV380:
rdev->asic = &r300_asic;
if (rdev->flags & RADEON_IS_PCIE) {
- rdev->asic->gart_init = &rv370_pcie_gart_init;
- rdev->asic->gart_fini = &rv370_pcie_gart_fini;
- rdev->asic->gart_enable = &rv370_pcie_gart_enable;
- rdev->asic->gart_disable = &rv370_pcie_gart_disable;
rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush;
rdev->asic->gart_set_page = &rv370_pcie_gart_set_page;
}
@@ -485,7 +481,6 @@ void radeon_combios_fini(struct radeon_device *rdev)
static unsigned int radeon_vga_set_decode(void *cookie, bool state)
{
struct radeon_device *rdev = cookie;
-
radeon_vga_set_state(rdev, state);
if (state)
return VGA_RSRC_LEGACY_IO | VGA_RSRC_LEGACY_MEM |
@@ -493,6 +488,29 @@ static unsigned int radeon_vga_set_decode(void *cookie, bool state)
else
return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM;
}
+
+void radeon_agp_disable(struct radeon_device *rdev)
+{
+ rdev->flags &= ~RADEON_IS_AGP;
+ if (rdev->family >= CHIP_R600) {
+ DRM_INFO("Forcing AGP to PCIE mode\n");
+ rdev->flags |= RADEON_IS_PCIE;
+ } else if (rdev->family >= CHIP_RV515 ||
+ rdev->family == CHIP_RV380 ||
+ rdev->family == CHIP_RV410 ||
+ rdev->family == CHIP_R423) {
+ DRM_INFO("Forcing AGP to PCIE mode\n");
+ rdev->flags |= RADEON_IS_PCIE;
+ rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush;
+ rdev->asic->gart_set_page = &rv370_pcie_gart_set_page;
+ } else {
+ DRM_INFO("Forcing AGP to PCI mode\n");
+ rdev->flags |= RADEON_IS_PCI;
+ rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush;
+ rdev->asic->gart_set_page = &r100_pci_gart_set_page;
+ }
+}
+
/*
* Radeon device.
*/
@@ -531,32 +549,7 @@ int radeon_device_init(struct radeon_device *rdev,
}
if (radeon_agpmode == -1) {
- rdev->flags &= ~RADEON_IS_AGP;
- if (rdev->family >= CHIP_R600) {
- DRM_INFO("Forcing AGP to PCIE mode\n");
- rdev->flags |= RADEON_IS_PCIE;
- } else if (rdev->family >= CHIP_RV515 ||
- rdev->family == CHIP_RV380 ||
- rdev->family == CHIP_RV410 ||
- rdev->family == CHIP_R423) {
- DRM_INFO("Forcing AGP to PCIE mode\n");
- rdev->flags |= RADEON_IS_PCIE;
- rdev->asic->gart_init = &rv370_pcie_gart_init;
- rdev->asic->gart_fini = &rv370_pcie_gart_fini;
- rdev->asic->gart_enable = &rv370_pcie_gart_enable;
- rdev->asic->gart_disable = &rv370_pcie_gart_disable;
- rdev->asic->gart_tlb_flush = &rv370_pcie_gart_tlb_flush;
- rdev->asic->gart_set_page = &rv370_pcie_gart_set_page;
- } else {
- DRM_INFO("Forcing AGP to PCI mode\n");
- rdev->flags |= RADEON_IS_PCI;
- rdev->asic->gart_init = &r100_pci_gart_init;
- rdev->asic->gart_fini = &r100_pci_gart_fini;
- rdev->asic->gart_enable = &r100_pci_gart_enable;
- rdev->asic->gart_disable = &r100_pci_gart_disable;
- rdev->asic->gart_tlb_flush = &r100_pci_gart_tlb_flush;
- rdev->asic->gart_set_page = &r100_pci_gart_set_page;
- }
+ radeon_agp_disable(rdev);
}
/* set DMA mask + need_dma32 flags.
@@ -588,111 +581,27 @@ int radeon_device_init(struct radeon_device *rdev,
DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size);
- rdev->new_init_path = false;
- r = radeon_init(rdev);
- if (r) {
- return r;
- }
-
/* if we have > 1 VGA cards, then disable the radeon VGA resources */
r = vga_client_register(rdev->pdev, rdev, NULL, radeon_vga_set_decode);
if (r) {
return -EINVAL;
}
- if (!rdev->new_init_path) {
- /* Setup errata flags */
- radeon_errata(rdev);
- /* Initialize scratch registers */
- radeon_scratch_init(rdev);
- /* Initialize surface registers */
- radeon_surface_init(rdev);
-
- /* BIOS*/
- if (!radeon_get_bios(rdev)) {
- if (ASIC_IS_AVIVO(rdev))
- return -EINVAL;
- }
- if (rdev->is_atom_bios) {
- r = radeon_atombios_init(rdev);
- if (r) {
- return r;
- }
- } else {
- r = radeon_combios_init(rdev);
- if (r) {
- return r;
- }
- }
- /* Reset gpu before posting otherwise ATOM will enter infinite loop */
- if (radeon_gpu_reset(rdev)) {
- /* FIXME: what do we want to do here ? */
- }
- /* check if cards are posted or not */
- if (!radeon_card_posted(rdev) && rdev->bios) {
- DRM_INFO("GPU not posted. posting now...\n");
- if (rdev->is_atom_bios) {
- atom_asic_init(rdev->mode_info.atom_context);
- } else {
- radeon_combios_asic_init(rdev->ddev);
- }
- }
- /* Get clock & vram information */
- radeon_get_clock_info(rdev->ddev);
- radeon_vram_info(rdev);
- /* Initialize clocks */
- r = radeon_clocks_init(rdev);
- if (r) {
- return r;
- }
+ r = radeon_init(rdev);
+ if (r)
+ return r;
- /* Initialize memory controller (also test AGP) */
- r = radeon_mc_init(rdev);
- if (r) {
- return r;
- }
- /* Fence driver */
- r = radeon_fence_driver_init(rdev);
- if (r) {
- return r;
- }
- r = radeon_irq_kms_init(rdev);
- if (r) {
- return r;
- }
- /* Memory manager */
- r = radeon_object_init(rdev);
- if (r) {
- return r;
- }
- r = radeon_gpu_gart_init(rdev);
+ if (rdev->flags & RADEON_IS_AGP && !rdev->accel_working) {
+ /* Acceleration not working on AGP card try again
+ * with fallback to PCI or PCIE GART
+ */
+ radeon_gpu_reset(rdev);
+ radeon_fini(rdev);
+ radeon_agp_disable(rdev);
+ r = radeon_init(rdev);
if (r)
return r;
- /* Initialize GART (initialize after TTM so we can allocate
- * memory through TTM but finalize after TTM) */
- r = radeon_gart_enable(rdev);
- if (r)
- return 0;
- r = radeon_gem_init(rdev);
- if (r)
- return 0;
-
- /* 1M ring buffer */
- r = radeon_cp_init(rdev, 1024 * 1024);
- if (r)
- return 0;
- r = radeon_wb_init(rdev);
- if (r)
- DRM_ERROR("radeon: failled initializing WB (%d).\n", r);
- r = radeon_ib_pool_init(rdev);
- if (r)
- return 0;
- r = radeon_ib_test(rdev);
- if (r)
- return 0;
- rdev->accel_working = true;
}
- DRM_INFO("radeon: kernel modesetting successfully initialized.\n");
if (radeon_testing) {
radeon_test_moves(rdev);
}
@@ -706,32 +615,8 @@ void radeon_device_fini(struct radeon_device *rdev)
{
DRM_INFO("radeon: finishing device.\n");
rdev->shutdown = true;
- /* Order matter so becarefull if you rearrange anythings */
- if (!rdev->new_init_path) {
- radeon_ib_pool_fini(rdev);
- radeon_cp_fini(rdev);
- radeon_wb_fini(rdev);
- radeon_gpu_gart_fini(rdev);
- radeon_gem_fini(rdev);
- radeon_mc_fini(rdev);
-#if __OS_HAS_AGP
- radeon_agp_fini(rdev);
-#endif
- radeon_irq_kms_fini(rdev);
- vga_client_register(rdev->pdev, NULL, NULL, NULL);
- radeon_fence_driver_fini(rdev);
- radeon_clocks_fini(rdev);
- radeon_object_fini(rdev);
- if (rdev->is_atom_bios) {
- radeon_atombios_fini(rdev);
- } else {
- radeon_combios_fini(rdev);
- }
- kfree(rdev->bios);
- rdev->bios = NULL;
- } else {
- radeon_fini(rdev);
- }
+ radeon_fini(rdev);
+ vga_client_register(rdev->pdev, NULL, NULL, NULL);
iounmap(rdev->rmmio);
rdev->rmmio = NULL;
}
@@ -771,14 +656,7 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
radeon_save_bios_scratch_regs(rdev);
- if (!rdev->new_init_path) {
- radeon_cp_disable(rdev);
- radeon_gart_disable(rdev);
- rdev->irq.sw_int = false;
- radeon_irq_set(rdev);
- } else {
- radeon_suspend(rdev);
- }
+ radeon_suspend(rdev);
/* evict remaining vram memory */
radeon_object_evict_vram(rdev);
@@ -797,7 +675,6 @@ int radeon_suspend_kms(struct drm_device *dev, pm_message_t state)
int radeon_resume_kms(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
- int r;
acquire_console_sem();
pci_set_power_state(dev->pdev, PCI_D0);
@@ -807,43 +684,7 @@ int radeon_resume_kms(struct drm_device *dev)
return -1;
}
pci_set_master(dev->pdev);
- /* Reset gpu before posting otherwise ATOM will enter infinite loop */
- if (!rdev->new_init_path) {
- if (radeon_gpu_reset(rdev)) {
- /* FIXME: what do we want to do here ? */
- }
- /* post card */
- if (rdev->is_atom_bios) {
- atom_asic_init(rdev->mode_info.atom_context);
- } else {
- radeon_combios_asic_init(rdev->ddev);
- }
- /* Initialize clocks */
- r = radeon_clocks_init(rdev);
- if (r) {
- release_console_sem();
- return r;
- }
- /* Enable IRQ */
- rdev->irq.sw_int = true;
- radeon_irq_set(rdev);
- /* Initialize GPU Memory Controller */
- r = radeon_mc_init(rdev);
- if (r) {
- goto out;
- }
- r = radeon_gart_enable(rdev);
- if (r) {
- goto out;
- }
- r = radeon_cp_init(rdev, rdev->cp.ring_size);
- if (r) {
- goto out;
- }
- } else {
- radeon_resume(rdev);
- }
-out:
+ radeon_resume(rdev);
radeon_restore_bios_scratch_regs(rdev);
fb_set_suspend(rdev->fbdev_info, 0);
release_console_sem();
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 5d8141b13765..a20bf43389b3 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -106,51 +106,44 @@ void radeon_crtc_load_lut(struct drm_crtc *crtc)
legacy_crtc_load_lut(crtc);
}
-/** Sets the color ramps on behalf of RandR */
+/** Sets the color ramps on behalf of fbcon */
void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
- if (regno == 0)
- DRM_DEBUG("gamma set %d\n", radeon_crtc->crtc_id);
radeon_crtc->lut_r[regno] = red >> 6;
radeon_crtc->lut_g[regno] = green >> 6;
radeon_crtc->lut_b[regno] = blue >> 6;
}
+/** Gets the color ramps on behalf of fbcon */
+void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno)
+{
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
+
+ *red = radeon_crtc->lut_r[regno] << 6;
+ *green = radeon_crtc->lut_g[regno] << 6;
+ *blue = radeon_crtc->lut_b[regno] << 6;
+}
+
static void radeon_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, uint32_t size)
{
struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
- int i, j;
+ int i;
if (size != 256) {
return;
}
- if (crtc->fb == NULL) {
- return;
- }
- if (crtc->fb->depth == 16) {
- for (i = 0; i < 64; i++) {
- if (i <= 31) {
- for (j = 0; j < 8; j++) {
- radeon_crtc->lut_r[i * 8 + j] = red[i] >> 6;
- radeon_crtc->lut_b[i * 8 + j] = blue[i] >> 6;
- }
- }
- for (j = 0; j < 4; j++)
- radeon_crtc->lut_g[i * 4 + j] = green[i] >> 6;
- }
- } else {
- for (i = 0; i < 256; i++) {
- radeon_crtc->lut_r[i] = red[i] >> 6;
- radeon_crtc->lut_g[i] = green[i] >> 6;
- radeon_crtc->lut_b[i] = blue[i] >> 6;
- }
+ /* userspace palettes are always correct as is */
+ for (i = 0; i < 256; i++) {
+ radeon_crtc->lut_r[i] = red[i] >> 6;
+ radeon_crtc->lut_g[i] = green[i] >> 6;
+ radeon_crtc->lut_b[i] = blue[i] >> 6;
}
-
radeon_crtc_load_lut(crtc);
}
@@ -724,7 +717,11 @@ int radeon_modeset_init(struct radeon_device *rdev)
if (ret) {
return ret;
}
- /* allocate crtcs - TODO single crtc */
+
+ if (rdev->flags & RADEON_SINGLE_CRTC)
+ num_crtc = 1;
+
+ /* allocate crtcs */
for (i = 0; i < num_crtc; i++) {
radeon_crtc_init(rdev->ddev, i);
}
@@ -764,7 +761,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) {
@@ -782,10 +779,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 621646752cd2..6cdef27be99d 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;
}
@@ -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);
@@ -1268,8 +1249,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)
@@ -1345,6 +1324,7 @@ radeon_atombios_set_dig_info(struct radeon_encoder *radeon_encoder)
void
radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t supported_device)
{
+ struct radeon_device *rdev = dev->dev_private;
struct drm_encoder *encoder;
struct radeon_encoder *radeon_encoder;
@@ -1364,7 +1344,10 @@ radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t su
return;
encoder = &radeon_encoder->base;
- encoder->possible_crtcs = 0x3;
+ if (rdev->flags & RADEON_SINGLE_CRTC)
+ encoder->possible_crtcs = 0x1;
+ else
+ encoder->possible_crtcs = 0x3;
encoder->possible_clones = 0;
radeon_encoder->enc_priv = NULL;
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 1ba704eedefb..b38c4c8e2c61 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -55,6 +55,7 @@ static struct fb_ops radeonfb_ops = {
.fb_imageblit = cfb_imageblit,
.fb_pan_display = drm_fb_helper_pan_display,
.fb_blank = drm_fb_helper_blank,
+ .fb_setcmap = drm_fb_helper_setcmap,
};
/**
@@ -123,6 +124,7 @@ static int radeon_align_pitch(struct radeon_device *rdev, int width, int bpp, bo
static struct drm_fb_helper_funcs radeon_fb_helper_funcs = {
.gamma_set = radeon_crtc_fb_gamma_set,
+ .gamma_get = radeon_crtc_fb_gamma_get,
};
int radeonfb_create(struct drm_device *dev,
@@ -146,9 +148,15 @@ int radeonfb_create(struct drm_device *dev,
unsigned long tmp;
bool fb_tiled = false; /* useful for testing */
u32 tiling_flags = 0;
+ int crtc_count;
mode_cmd.width = surface_width;
mode_cmd.height = surface_height;
+
+ /* avivo can't scanout real 24bpp */
+ if ((surface_bpp == 24) && ASIC_IS_AVIVO(rdev))
+ surface_bpp = 32;
+
mode_cmd.bpp = surface_bpp;
/* need to align pitch with crtc limits */
mode_cmd.pitch = radeon_align_pitch(rdev, mode_cmd.width, mode_cmd.bpp, fb_tiled) * ((mode_cmd.bpp + 1) / 8);
@@ -217,7 +225,11 @@ int radeonfb_create(struct drm_device *dev,
rfbdev = info->par;
rfbdev->helper.funcs = &radeon_fb_helper_funcs;
rfbdev->helper.dev = dev;
- ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, 2,
+ if (rdev->flags & RADEON_SINGLE_CRTC)
+ crtc_count = 1;
+ else
+ crtc_count = 2;
+ ret = drm_fb_helper_init_crtc_count(&rfbdev->helper, crtc_count,
RADEONFB_CONN_LIMIT);
if (ret)
goto out_unref;
@@ -234,7 +246,7 @@ int radeonfb_create(struct drm_device *dev,
strcpy(info->fix.id, "radeondrmfb");
- drm_fb_helper_fill_fix(info, fb->pitch);
+ drm_fb_helper_fill_fix(info, fb->pitch, fb->depth);
info->flags = FBINFO_DEFAULT;
info->fbops = &radeonfb_ops;
@@ -309,7 +321,7 @@ int radeon_parse_options(char *options)
int radeonfb_probe(struct drm_device *dev)
{
- return drm_fb_helper_single_fb_probe(dev, &radeonfb_create);
+ return drm_fb_helper_single_fb_probe(dev, 32, &radeonfb_create);
}
int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb)
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c
index 1841145a7c4f..8e0a8759e428 100644
--- a/drivers/gpu/drm/radeon/radeon_irq_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c
@@ -83,8 +83,12 @@ void radeon_driver_irq_uninstall_kms(struct drm_device *dev)
int radeon_irq_kms_init(struct radeon_device *rdev)
{
int r = 0;
+ int num_crtc = 2;
- r = drm_vblank_init(rdev->ddev, 2);
+ if (rdev->flags & RADEON_SINGLE_CRTC)
+ num_crtc = 1;
+
+ r = drm_vblank_init(rdev->ddev, num_crtc);
if (r) {
return r;
}
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c
index 2b997a15fb1f..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 {
@@ -1053,6 +1057,7 @@ static const struct drm_crtc_helper_funcs legacy_helper_funcs = {
.mode_set_base = radeon_crtc_set_base,
.prepare = radeon_crtc_prepare,
.commit = radeon_crtc_commit,
+ .load_lut = radeon_crtc_load_lut,
};
diff --git a/drivers/gpu/drm/radeon/radeon_legacy_encoders.c b/drivers/gpu/drm/radeon/radeon_legacy_encoders.c
index b1547f700d73..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)
@@ -881,7 +888,7 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
R420_TV_DAC_DACADJ_MASK |
R420_TV_DAC_RDACPD |
R420_TV_DAC_GDACPD |
- R420_TV_DAC_GDACPD |
+ R420_TV_DAC_BDACPD |
R420_TV_DAC_TVENABLE);
} else {
tv_dac_cntl &= ~(RADEON_TV_DAC_STD_MASK |
@@ -889,7 +896,7 @@ static void radeon_legacy_tv_dac_mode_set(struct drm_encoder *encoder,
RADEON_TV_DAC_DACADJ_MASK |
RADEON_TV_DAC_RDACPD |
RADEON_TV_DAC_GDACPD |
- RADEON_TV_DAC_GDACPD);
+ RADEON_TV_DAC_BDACPD);
}
/* FIXME TV */
@@ -1318,7 +1325,10 @@ radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_id, uint32_t
return;
encoder = &radeon_encoder->base;
- encoder->possible_crtcs = 0x3;
+ if (rdev->flags & RADEON_SINGLE_CRTC)
+ encoder->possible_crtcs = 0x1;
+ else
+ encoder->possible_crtcs = 0x3;
encoder->possible_clones = 0;
radeon_encoder->enc_priv = NULL;
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 570a58729daf..3d2631be073c 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 {
@@ -279,7 +268,7 @@ struct radeon_encoder_atom_dig {
uint32_t lvds_misc;
uint16_t panel_pwr_delay;
/* panel mode */
- struct radeon_native_mode native_mode;
+ struct drm_display_mode native_mode;
};
struct radeon_encoder_atom_dac {
@@ -294,7 +283,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;
};
@@ -407,6 +396,8 @@ extern void
radeon_combios_encoder_dpms_scratch_regs(struct drm_encoder *encoder, bool on);
extern void radeon_crtc_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno);
+extern void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno);
struct drm_framebuffer *radeon_framebuffer_create(struct drm_device *dev,
struct drm_mode_fb_cmd *mode_cmd,
struct drm_gem_object *obj);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 73af463b7a59..1f056dadc5c2 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -400,11 +400,9 @@ void radeon_object_list_add_object(struct radeon_object_list *lobj,
int radeon_object_list_reserve(struct list_head *head)
{
struct radeon_object_list *lobj;
- struct list_head *i;
int r;
- list_for_each(i, head) {
- lobj = list_entry(i, struct radeon_object_list, list);
+ list_for_each_entry(lobj, head, list){
if (!lobj->robj->pin_count) {
r = radeon_object_reserve(lobj->robj, true);
if (unlikely(r != 0)) {
@@ -420,13 +418,10 @@ int radeon_object_list_reserve(struct list_head *head)
void radeon_object_list_unreserve(struct list_head *head)
{
struct radeon_object_list *lobj;
- struct list_head *i;
- list_for_each(i, head) {
- lobj = list_entry(i, struct radeon_object_list, list);
+ list_for_each_entry(lobj, head, list) {
if (!lobj->robj->pin_count) {
radeon_object_unreserve(lobj->robj);
- } else {
}
}
}
@@ -436,7 +431,6 @@ int radeon_object_list_validate(struct list_head *head, void *fence)
struct radeon_object_list *lobj;
struct radeon_object *robj;
struct radeon_fence *old_fence = NULL;
- struct list_head *i;
int r;
r = radeon_object_list_reserve(head);
@@ -444,8 +438,7 @@ int radeon_object_list_validate(struct list_head *head, void *fence)
radeon_object_list_unreserve(head);
return r;
}
- list_for_each(i, head) {
- lobj = list_entry(i, struct radeon_object_list, list);
+ list_for_each_entry(lobj, head, list) {
robj = lobj->robj;
if (!robj->pin_count) {
if (lobj->wdomain) {
@@ -482,10 +475,8 @@ void radeon_object_list_unvalidate(struct list_head *head)
{
struct radeon_object_list *lobj;
struct radeon_fence *old_fence = NULL;
- struct list_head *i;
- list_for_each(i, head) {
- lobj = list_entry(i, struct radeon_object_list, list);
+ list_for_each_entry(lobj, head, list) {
old_fence = (struct radeon_fence *)lobj->robj->tobj.sync_obj;
lobj->robj->tobj.sync_obj = NULL;
if (old_fence) {
diff --git a/drivers/gpu/drm/radeon/rs100d.h b/drivers/gpu/drm/radeon/rs100d.h
new file mode 100644
index 000000000000..48a913a06cfd
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs100d.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#ifndef __RS100D_H__
+#define __RS100D_H__
+
+/* Registers */
+#define R_00015C_NB_TOM 0x00015C
+#define S_00015C_MC_FB_START(x) (((x) & 0xFFFF) << 0)
+#define G_00015C_MC_FB_START(x) (((x) >> 0) & 0xFFFF)
+#define C_00015C_MC_FB_START 0xFFFF0000
+#define S_00015C_MC_FB_TOP(x) (((x) & 0xFFFF) << 16)
+#define G_00015C_MC_FB_TOP(x) (((x) >> 16) & 0xFFFF)
+#define C_00015C_MC_FB_TOP 0x0000FFFF
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c
index a3fbdad938c7..a769c296f6a6 100644
--- a/drivers/gpu/drm/radeon/rs400.c
+++ b/drivers/gpu/drm/radeon/rs400.c
@@ -27,27 +27,12 @@
*/
#include <linux/seq_file.h>
#include <drm/drmP.h>
-#include "radeon_reg.h"
#include "radeon.h"
+#include "rs400d.h"
-/* rs400,rs480 depends on : */
-void r100_hdp_reset(struct radeon_device *rdev);
-void r100_mc_disable_clients(struct radeon_device *rdev);
-int r300_mc_wait_for_idle(struct radeon_device *rdev);
-void r420_pipes_init(struct radeon_device *rdev);
+/* This files gather functions specifics to : rs400,rs480 */
+static int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev);
-/* This files gather functions specifics to :
- * rs400,rs480
- *
- * Some of these functions might be used by newer ASICs.
- */
-void rs400_gpu_init(struct radeon_device *rdev);
-int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev);
-
-
-/*
- * GART functions.
- */
void rs400_gart_adjust_size(struct radeon_device *rdev)
{
/* Check gart size */
@@ -238,61 +223,6 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
return 0;
}
-
-/*
- * MC functions.
- */
-int rs400_mc_init(struct radeon_device *rdev)
-{
- uint32_t tmp;
- int r;
-
- if (r100_debugfs_rbbm_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for RBBM !\n");
- }
-
- rs400_gpu_init(rdev);
- rs400_gart_disable(rdev);
- rdev->mc.gtt_location = rdev->mc.mc_vram_size;
- rdev->mc.gtt_location += (rdev->mc.gtt_size - 1);
- rdev->mc.gtt_location &= ~(rdev->mc.gtt_size - 1);
- r = radeon_mc_setup(rdev);
- if (r) {
- return r;
- }
-
- r100_mc_disable_clients(rdev);
- if (r300_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "Failed to wait MC idle while "
- "programming pipes. Bad things might happen.\n");
- }
-
- tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
- tmp = REG_SET(RADEON_MC_FB_TOP, tmp >> 16);
- tmp |= REG_SET(RADEON_MC_FB_START, rdev->mc.vram_location >> 16);
- WREG32(RADEON_MC_FB_LOCATION, tmp);
- tmp = RREG32(RADEON_HOST_PATH_CNTL) | RADEON_HP_LIN_RD_CACHE_DIS;
- WREG32(RADEON_HOST_PATH_CNTL, tmp | RADEON_HDP_SOFT_RESET | RADEON_HDP_READ_BUFFER_INVALIDATE);
- (void)RREG32(RADEON_HOST_PATH_CNTL);
- WREG32(RADEON_HOST_PATH_CNTL, tmp);
- (void)RREG32(RADEON_HOST_PATH_CNTL);
-
- return 0;
-}
-
-void rs400_mc_fini(struct radeon_device *rdev)
-{
-}
-
-
-/*
- * Global GPU functions
- */
-void rs400_errata(struct radeon_device *rdev)
-{
- rdev->pll_errata = 0;
-}
-
void rs400_gpu_init(struct radeon_device *rdev)
{
/* FIXME: HDP same place on rs400 ? */
@@ -305,10 +235,6 @@ void rs400_gpu_init(struct radeon_device *rdev)
}
}
-
-/*
- * VRAM info.
- */
void rs400_vram_info(struct radeon_device *rdev)
{
rs400_gart_adjust_size(rdev);
@@ -319,10 +245,6 @@ void rs400_vram_info(struct radeon_device *rdev)
r100_vram_init_sizes(rdev);
}
-
-/*
- * Indirect registers accessor
- */
uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg)
{
uint32_t r;
@@ -340,10 +262,6 @@ void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
WREG32(RS480_NB_MC_INDEX, 0xff);
}
-
-/*
- * Debugfs info
- */
#if defined(CONFIG_DEBUG_FS)
static int rs400_debugfs_gart_info(struct seq_file *m, void *data)
{
@@ -419,7 +337,7 @@ static struct drm_info_list rs400_gart_info_list[] = {
};
#endif
-int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev)
+static int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev)
{
#if defined(CONFIG_DEBUG_FS)
return radeon_debugfs_add_files(rdev, rs400_gart_info_list, 1);
@@ -427,3 +345,188 @@ int rs400_debugfs_pcie_gart_info_init(struct radeon_device *rdev)
return 0;
#endif
}
+
+static int rs400_mc_init(struct radeon_device *rdev)
+{
+ int r;
+ u32 tmp;
+
+ /* Setup GPU memory space */
+ tmp = G_00015C_MC_FB_START(RREG32(R_00015C_NB_TOM));
+ rdev->mc.vram_location = G_00015C_MC_FB_START(tmp) << 16;
+ rdev->mc.gtt_location = 0xFFFFFFFFUL;
+ r = radeon_mc_setup(rdev);
+ if (r)
+ return r;
+ return 0;
+}
+
+void rs400_mc_program(struct radeon_device *rdev)
+{
+ struct r100_mc_save save;
+
+ /* Stops all mc clients */
+ r100_mc_stop(rdev, &save);
+
+ /* Wait for mc idle */
+ if (r300_mc_wait_for_idle(rdev))
+ dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n");
+ WREG32(R_000148_MC_FB_LOCATION,
+ S_000148_MC_FB_START(rdev->mc.vram_start >> 16) |
+ S_000148_MC_FB_TOP(rdev->mc.vram_end >> 16));
+
+ r100_mc_resume(rdev, &save);
+}
+
+static int rs400_startup(struct radeon_device *rdev)
+{
+ int r;
+
+ rs400_mc_program(rdev);
+ /* Resume clock */
+ r300_clock_startup(rdev);
+ /* Initialize GPU configuration (# pipes, ...) */
+ rs400_gpu_init(rdev);
+ /* Initialize GART (initialize after TTM so we can allocate
+ * memory through TTM but finalize after TTM) */
+ r = rs400_gart_enable(rdev);
+ if (r)
+ return r;
+ /* Enable IRQ */
+ rdev->irq.sw_int = true;
+ r100_irq_set(rdev);
+ /* 1M ring buffer */
+ r = r100_cp_init(rdev, 1024 * 1024);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ return r;
+ }
+ r = r100_wb_init(rdev);
+ if (r)
+ dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
+ r = r100_ib_init(rdev);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ return r;
+ }
+ return 0;
+}
+
+int rs400_resume(struct radeon_device *rdev)
+{
+ /* Make sur GART are not working */
+ rs400_gart_disable(rdev);
+ /* Resume clock before doing reset */
+ r300_clock_startup(rdev);
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_reset(rdev)) {
+ dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
+ RREG32(R_000E40_RBBM_STATUS),
+ RREG32(R_0007C0_CP_STAT));
+ }
+ /* post */
+ radeon_combios_asic_init(rdev->ddev);
+ /* Resume clock after posting */
+ r300_clock_startup(rdev);
+ return rs400_startup(rdev);
+}
+
+int rs400_suspend(struct radeon_device *rdev)
+{
+ r100_cp_disable(rdev);
+ r100_wb_disable(rdev);
+ r100_irq_disable(rdev);
+ rs400_gart_disable(rdev);
+ return 0;
+}
+
+void rs400_fini(struct radeon_device *rdev)
+{
+ rs400_suspend(rdev);
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ radeon_gem_fini(rdev);
+ rs400_gart_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ radeon_fence_driver_fini(rdev);
+ radeon_object_fini(rdev);
+ radeon_atombios_fini(rdev);
+ kfree(rdev->bios);
+ rdev->bios = NULL;
+}
+
+int rs400_init(struct radeon_device *rdev)
+{
+ int r;
+
+ /* Disable VGA */
+ r100_vga_render_disable(rdev);
+ /* Initialize scratch registers */
+ radeon_scratch_init(rdev);
+ /* Initialize surface registers */
+ radeon_surface_init(rdev);
+ /* TODO: disable VGA need to use VGA request */
+ /* BIOS*/
+ if (!radeon_get_bios(rdev)) {
+ if (ASIC_IS_AVIVO(rdev))
+ return -EINVAL;
+ }
+ if (rdev->is_atom_bios) {
+ dev_err(rdev->dev, "Expecting combios for RS400/RS480 GPU\n");
+ return -EINVAL;
+ } else {
+ r = radeon_combios_init(rdev);
+ if (r)
+ return r;
+ }
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_reset(rdev)) {
+ dev_warn(rdev->dev,
+ "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
+ RREG32(R_000E40_RBBM_STATUS),
+ RREG32(R_0007C0_CP_STAT));
+ }
+ /* check if cards are posted or not */
+ if (!radeon_card_posted(rdev) && rdev->bios) {
+ DRM_INFO("GPU not posted. posting now...\n");
+ radeon_combios_asic_init(rdev->ddev);
+ }
+ /* Initialize clocks */
+ radeon_get_clock_info(rdev->ddev);
+ /* Get vram informations */
+ rs400_vram_info(rdev);
+ /* Initialize memory controller (also test AGP) */
+ r = rs400_mc_init(rdev);
+ if (r)
+ return r;
+ /* Fence driver */
+ r = radeon_fence_driver_init(rdev);
+ if (r)
+ return r;
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ /* Memory manager */
+ r = radeon_object_init(rdev);
+ if (r)
+ return r;
+ r = rs400_gart_init(rdev);
+ if (r)
+ return r;
+ r300_set_reg_safe(rdev);
+ rdev->accel_working = true;
+ r = rs400_startup(rdev);
+ if (r) {
+ /* Somethings want wront with the accel init stop accel */
+ dev_err(rdev->dev, "Disabling GPU acceleration\n");
+ rs400_suspend(rdev);
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ rs400_gart_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ rdev->accel_working = false;
+ }
+ return 0;
+}
diff --git a/drivers/gpu/drm/radeon/rs400d.h b/drivers/gpu/drm/radeon/rs400d.h
new file mode 100644
index 000000000000..6d8bac58ced9
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs400d.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#ifndef __RS400D_H__
+#define __RS400D_H__
+
+/* Registers */
+#define R_000148_MC_FB_LOCATION 0x000148
+#define S_000148_MC_FB_START(x) (((x) & 0xFFFF) << 0)
+#define G_000148_MC_FB_START(x) (((x) >> 0) & 0xFFFF)
+#define C_000148_MC_FB_START 0xFFFF0000
+#define S_000148_MC_FB_TOP(x) (((x) & 0xFFFF) << 16)
+#define G_000148_MC_FB_TOP(x) (((x) >> 16) & 0xFFFF)
+#define C_000148_MC_FB_TOP 0x0000FFFF
+#define R_00015C_NB_TOM 0x00015C
+#define S_00015C_MC_FB_START(x) (((x) & 0xFFFF) << 0)
+#define G_00015C_MC_FB_START(x) (((x) >> 0) & 0xFFFF)
+#define C_00015C_MC_FB_START 0xFFFF0000
+#define S_00015C_MC_FB_TOP(x) (((x) & 0xFFFF) << 16)
+#define G_00015C_MC_FB_TOP(x) (((x) >> 16) & 0xFFFF)
+#define C_00015C_MC_FB_TOP 0x0000FFFF
+#define R_0007C0_CP_STAT 0x0007C0
+#define S_0007C0_MRU_BUSY(x) (((x) & 0x1) << 0)
+#define G_0007C0_MRU_BUSY(x) (((x) >> 0) & 0x1)
+#define C_0007C0_MRU_BUSY 0xFFFFFFFE
+#define S_0007C0_MWU_BUSY(x) (((x) & 0x1) << 1)
+#define G_0007C0_MWU_BUSY(x) (((x) >> 1) & 0x1)
+#define C_0007C0_MWU_BUSY 0xFFFFFFFD
+#define S_0007C0_RSIU_BUSY(x) (((x) & 0x1) << 2)
+#define G_0007C0_RSIU_BUSY(x) (((x) >> 2) & 0x1)
+#define C_0007C0_RSIU_BUSY 0xFFFFFFFB
+#define S_0007C0_RCIU_BUSY(x) (((x) & 0x1) << 3)
+#define G_0007C0_RCIU_BUSY(x) (((x) >> 3) & 0x1)
+#define C_0007C0_RCIU_BUSY 0xFFFFFFF7
+#define S_0007C0_CSF_PRIMARY_BUSY(x) (((x) & 0x1) << 9)
+#define G_0007C0_CSF_PRIMARY_BUSY(x) (((x) >> 9) & 0x1)
+#define C_0007C0_CSF_PRIMARY_BUSY 0xFFFFFDFF
+#define S_0007C0_CSF_INDIRECT_BUSY(x) (((x) & 0x1) << 10)
+#define G_0007C0_CSF_INDIRECT_BUSY(x) (((x) >> 10) & 0x1)
+#define C_0007C0_CSF_INDIRECT_BUSY 0xFFFFFBFF
+#define S_0007C0_CSQ_PRIMARY_BUSY(x) (((x) & 0x1) << 11)
+#define G_0007C0_CSQ_PRIMARY_BUSY(x) (((x) >> 11) & 0x1)
+#define C_0007C0_CSQ_PRIMARY_BUSY 0xFFFFF7FF
+#define S_0007C0_CSQ_INDIRECT_BUSY(x) (((x) & 0x1) << 12)
+#define G_0007C0_CSQ_INDIRECT_BUSY(x) (((x) >> 12) & 0x1)
+#define C_0007C0_CSQ_INDIRECT_BUSY 0xFFFFEFFF
+#define S_0007C0_CSI_BUSY(x) (((x) & 0x1) << 13)
+#define G_0007C0_CSI_BUSY(x) (((x) >> 13) & 0x1)
+#define C_0007C0_CSI_BUSY 0xFFFFDFFF
+#define S_0007C0_CSF_INDIRECT2_BUSY(x) (((x) & 0x1) << 14)
+#define G_0007C0_CSF_INDIRECT2_BUSY(x) (((x) >> 14) & 0x1)
+#define C_0007C0_CSF_INDIRECT2_BUSY 0xFFFFBFFF
+#define S_0007C0_CSQ_INDIRECT2_BUSY(x) (((x) & 0x1) << 15)
+#define G_0007C0_CSQ_INDIRECT2_BUSY(x) (((x) >> 15) & 0x1)
+#define C_0007C0_CSQ_INDIRECT2_BUSY 0xFFFF7FFF
+#define S_0007C0_GUIDMA_BUSY(x) (((x) & 0x1) << 28)
+#define G_0007C0_GUIDMA_BUSY(x) (((x) >> 28) & 0x1)
+#define C_0007C0_GUIDMA_BUSY 0xEFFFFFFF
+#define S_0007C0_VIDDMA_BUSY(x) (((x) & 0x1) << 29)
+#define G_0007C0_VIDDMA_BUSY(x) (((x) >> 29) & 0x1)
+#define C_0007C0_VIDDMA_BUSY 0xDFFFFFFF
+#define S_0007C0_CMDSTRM_BUSY(x) (((x) & 0x1) << 30)
+#define G_0007C0_CMDSTRM_BUSY(x) (((x) >> 30) & 0x1)
+#define C_0007C0_CMDSTRM_BUSY 0xBFFFFFFF
+#define S_0007C0_CP_BUSY(x) (((x) & 0x1) << 31)
+#define G_0007C0_CP_BUSY(x) (((x) >> 31) & 0x1)
+#define C_0007C0_CP_BUSY 0x7FFFFFFF
+#define R_000E40_RBBM_STATUS 0x000E40
+#define S_000E40_CMDFIFO_AVAIL(x) (((x) & 0x7F) << 0)
+#define G_000E40_CMDFIFO_AVAIL(x) (((x) >> 0) & 0x7F)
+#define C_000E40_CMDFIFO_AVAIL 0xFFFFFF80
+#define S_000E40_HIRQ_ON_RBB(x) (((x) & 0x1) << 8)
+#define G_000E40_HIRQ_ON_RBB(x) (((x) >> 8) & 0x1)
+#define C_000E40_HIRQ_ON_RBB 0xFFFFFEFF
+#define S_000E40_CPRQ_ON_RBB(x) (((x) & 0x1) << 9)
+#define G_000E40_CPRQ_ON_RBB(x) (((x) >> 9) & 0x1)
+#define C_000E40_CPRQ_ON_RBB 0xFFFFFDFF
+#define S_000E40_CFRQ_ON_RBB(x) (((x) & 0x1) << 10)
+#define G_000E40_CFRQ_ON_RBB(x) (((x) >> 10) & 0x1)
+#define C_000E40_CFRQ_ON_RBB 0xFFFFFBFF
+#define S_000E40_HIRQ_IN_RTBUF(x) (((x) & 0x1) << 11)
+#define G_000E40_HIRQ_IN_RTBUF(x) (((x) >> 11) & 0x1)
+#define C_000E40_HIRQ_IN_RTBUF 0xFFFFF7FF
+#define S_000E40_CPRQ_IN_RTBUF(x) (((x) & 0x1) << 12)
+#define G_000E40_CPRQ_IN_RTBUF(x) (((x) >> 12) & 0x1)
+#define C_000E40_CPRQ_IN_RTBUF 0xFFFFEFFF
+#define S_000E40_CFRQ_IN_RTBUF(x) (((x) & 0x1) << 13)
+#define G_000E40_CFRQ_IN_RTBUF(x) (((x) >> 13) & 0x1)
+#define C_000E40_CFRQ_IN_RTBUF 0xFFFFDFFF
+#define S_000E40_CF_PIPE_BUSY(x) (((x) & 0x1) << 14)
+#define G_000E40_CF_PIPE_BUSY(x) (((x) >> 14) & 0x1)
+#define C_000E40_CF_PIPE_BUSY 0xFFFFBFFF
+#define S_000E40_ENG_EV_BUSY(x) (((x) & 0x1) << 15)
+#define G_000E40_ENG_EV_BUSY(x) (((x) >> 15) & 0x1)
+#define C_000E40_ENG_EV_BUSY 0xFFFF7FFF
+#define S_000E40_CP_CMDSTRM_BUSY(x) (((x) & 0x1) << 16)
+#define G_000E40_CP_CMDSTRM_BUSY(x) (((x) >> 16) & 0x1)
+#define C_000E40_CP_CMDSTRM_BUSY 0xFFFEFFFF
+#define S_000E40_E2_BUSY(x) (((x) & 0x1) << 17)
+#define G_000E40_E2_BUSY(x) (((x) >> 17) & 0x1)
+#define C_000E40_E2_BUSY 0xFFFDFFFF
+#define S_000E40_RB2D_BUSY(x) (((x) & 0x1) << 18)
+#define G_000E40_RB2D_BUSY(x) (((x) >> 18) & 0x1)
+#define C_000E40_RB2D_BUSY 0xFFFBFFFF
+#define S_000E40_RB3D_BUSY(x) (((x) & 0x1) << 19)
+#define G_000E40_RB3D_BUSY(x) (((x) >> 19) & 0x1)
+#define C_000E40_RB3D_BUSY 0xFFF7FFFF
+#define S_000E40_VAP_BUSY(x) (((x) & 0x1) << 20)
+#define G_000E40_VAP_BUSY(x) (((x) >> 20) & 0x1)
+#define C_000E40_VAP_BUSY 0xFFEFFFFF
+#define S_000E40_RE_BUSY(x) (((x) & 0x1) << 21)
+#define G_000E40_RE_BUSY(x) (((x) >> 21) & 0x1)
+#define C_000E40_RE_BUSY 0xFFDFFFFF
+#define S_000E40_TAM_BUSY(x) (((x) & 0x1) << 22)
+#define G_000E40_TAM_BUSY(x) (((x) >> 22) & 0x1)
+#define C_000E40_TAM_BUSY 0xFFBFFFFF
+#define S_000E40_TDM_BUSY(x) (((x) & 0x1) << 23)
+#define G_000E40_TDM_BUSY(x) (((x) >> 23) & 0x1)
+#define C_000E40_TDM_BUSY 0xFF7FFFFF
+#define S_000E40_PB_BUSY(x) (((x) & 0x1) << 24)
+#define G_000E40_PB_BUSY(x) (((x) >> 24) & 0x1)
+#define C_000E40_PB_BUSY 0xFEFFFFFF
+#define S_000E40_TIM_BUSY(x) (((x) & 0x1) << 25)
+#define G_000E40_TIM_BUSY(x) (((x) >> 25) & 0x1)
+#define C_000E40_TIM_BUSY 0xFDFFFFFF
+#define S_000E40_GA_BUSY(x) (((x) & 0x1) << 26)
+#define G_000E40_GA_BUSY(x) (((x) >> 26) & 0x1)
+#define C_000E40_GA_BUSY 0xFBFFFFFF
+#define S_000E40_CBA2D_BUSY(x) (((x) & 0x1) << 27)
+#define G_000E40_CBA2D_BUSY(x) (((x) >> 27) & 0x1)
+#define C_000E40_CBA2D_BUSY 0xF7FFFFFF
+#define S_000E40_GUI_ACTIVE(x) (((x) & 0x1) << 31)
+#define G_000E40_GUI_ACTIVE(x) (((x) >> 31) & 0x1)
+#define C_000E40_GUI_ACTIVE 0x7FFFFFFF
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 4a4fe1cb131c..10dfa78762da 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -25,27 +25,26 @@
* Alex Deucher
* Jerome Glisse
*/
+/* RS600 / Radeon X1250/X1270 integrated GPU
+ *
+ * This file gather function specific to RS600 which is the IGP of
+ * the X1250/X1270 family supporting intel CPU (while RS690/RS740
+ * is the X1250/X1270 supporting AMD CPU). The display engine are
+ * the avivo one, bios is an atombios, 3D block are the one of the
+ * R4XX family. The GART is different from the RS400 one and is very
+ * close to the one of the R600 family (R600 likely being an evolution
+ * of the RS600 GART block).
+ */
#include "drmP.h"
-#include "radeon_reg.h"
#include "radeon.h"
+#include "atom.h"
+#include "rs600d.h"
#include "rs600_reg_safe.h"
-/* rs600 depends on : */
-void r100_hdp_reset(struct radeon_device *rdev);
-int r100_gui_wait_for_idle(struct radeon_device *rdev);
-int r300_mc_wait_for_idle(struct radeon_device *rdev);
-void r420_pipes_init(struct radeon_device *rdev);
-
-/* This files gather functions specifics to :
- * rs600
- *
- * Some of these functions might be used by newer ASICs.
- */
void rs600_gpu_init(struct radeon_device *rdev);
int rs600_mc_wait_for_idle(struct radeon_device *rdev);
-
/*
* GART.
*/
@@ -53,18 +52,18 @@ void rs600_gart_tlb_flush(struct radeon_device *rdev)
{
uint32_t tmp;
- tmp = RREG32_MC(RS600_MC_PT0_CNTL);
- tmp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
- WREG32_MC(RS600_MC_PT0_CNTL, tmp);
+ tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
+ tmp &= C_000100_INVALIDATE_ALL_L1_TLBS & C_000100_INVALIDATE_L2_CACHE;
+ WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
- tmp = RREG32_MC(RS600_MC_PT0_CNTL);
- tmp |= RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE;
- WREG32_MC(RS600_MC_PT0_CNTL, tmp);
+ tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
+ tmp |= S_000100_INVALIDATE_ALL_L1_TLBS(1) & S_000100_INVALIDATE_L2_CACHE(1);
+ WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
- tmp = RREG32_MC(RS600_MC_PT0_CNTL);
- tmp &= ~(RS600_INVALIDATE_ALL_L1_TLBS | RS600_INVALIDATE_L2_CACHE);
- WREG32_MC(RS600_MC_PT0_CNTL, tmp);
- tmp = RREG32_MC(RS600_MC_PT0_CNTL);
+ tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
+ tmp &= C_000100_INVALIDATE_ALL_L1_TLBS & C_000100_INVALIDATE_L2_CACHE;
+ WREG32_MC(R_000100_MC_PT0_CNTL, tmp);
+ tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
}
int rs600_gart_init(struct radeon_device *rdev)
@@ -86,7 +85,7 @@ int rs600_gart_init(struct radeon_device *rdev)
int rs600_gart_enable(struct radeon_device *rdev)
{
- uint32_t tmp;
+ u32 tmp;
int r, i;
if (rdev->gart.table.vram.robj == NULL) {
@@ -96,46 +95,50 @@ int rs600_gart_enable(struct radeon_device *rdev)
r = radeon_gart_table_vram_pin(rdev);
if (r)
return r;
+ /* Enable bus master */
+ tmp = RREG32(R_00004C_BUS_CNTL) & C_00004C_BUS_MASTER_DIS;
+ WREG32(R_00004C_BUS_CNTL, tmp);
/* FIXME: setup default page */
- WREG32_MC(RS600_MC_PT0_CNTL,
- (RS600_EFFECTIVE_L2_CACHE_SIZE(6) |
- RS600_EFFECTIVE_L2_QUEUE_SIZE(6)));
+ WREG32_MC(R_000100_MC_PT0_CNTL,
+ (S_000100_EFFECTIVE_L2_CACHE_SIZE(6) |
+ S_000100_EFFECTIVE_L2_QUEUE_SIZE(6)));
for (i = 0; i < 19; i++) {
- WREG32_MC(RS600_MC_PT0_CLIENT0_CNTL + i,
- (RS600_ENABLE_TRANSLATION_MODE_OVERRIDE |
- RS600_SYSTEM_ACCESS_MODE_IN_SYS |
- RS600_SYSTEM_APERTURE_UNMAPPED_ACCESS_DEFAULT_PAGE |
- RS600_EFFECTIVE_L1_CACHE_SIZE(3) |
- RS600_ENABLE_FRAGMENT_PROCESSING |
- RS600_EFFECTIVE_L1_QUEUE_SIZE(3)));
+ WREG32_MC(R_00016C_MC_PT0_CLIENT0_CNTL + i,
+ S_00016C_ENABLE_TRANSLATION_MODE_OVERRIDE(1) |
+ S_00016C_SYSTEM_ACCESS_MODE_MASK(
+ V_00016C_SYSTEM_ACCESS_MODE_IN_SYS) |
+ S_00016C_SYSTEM_APERTURE_UNMAPPED_ACCESS(
+ V_00016C_SYSTEM_APERTURE_UNMAPPED_DEFAULT_PAGE) |
+ S_00016C_EFFECTIVE_L1_CACHE_SIZE(1) |
+ S_00016C_ENABLE_FRAGMENT_PROCESSING(1) |
+ S_00016C_EFFECTIVE_L1_QUEUE_SIZE(1));
}
/* System context map to GART space */
- WREG32_MC(RS600_MC_PT0_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.gtt_location);
- tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
- WREG32_MC(RS600_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR, tmp);
+ WREG32_MC(R_000112_MC_PT0_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.gtt_start);
+ WREG32_MC(R_000114_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR, rdev->mc.gtt_end);
/* enable first context */
- WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_START_ADDR, rdev->mc.gtt_location);
- tmp = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
- WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_END_ADDR, tmp);
- WREG32_MC(RS600_MC_PT0_CONTEXT0_CNTL,
- (RS600_ENABLE_PAGE_TABLE | RS600_PAGE_TABLE_TYPE_FLAT));
+ WREG32_MC(R_00013C_MC_PT0_CONTEXT0_FLAT_START_ADDR, rdev->mc.gtt_start);
+ WREG32_MC(R_00014C_MC_PT0_CONTEXT0_FLAT_END_ADDR, rdev->mc.gtt_end);
+ WREG32_MC(R_000102_MC_PT0_CONTEXT0_CNTL,
+ S_000102_ENABLE_PAGE_TABLE(1) |
+ S_000102_PAGE_TABLE_DEPTH(V_000102_PAGE_TABLE_FLAT));
/* disable all other contexts */
for (i = 1; i < 8; i++) {
- WREG32_MC(RS600_MC_PT0_CONTEXT0_CNTL + i, 0);
+ WREG32_MC(R_000102_MC_PT0_CONTEXT0_CNTL + i, 0);
}
/* setup the page table */
- WREG32_MC(RS600_MC_PT0_CONTEXT0_FLAT_BASE_ADDR,
- rdev->gart.table_addr);
- WREG32_MC(RS600_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0);
+ WREG32_MC(R_00012C_MC_PT0_CONTEXT0_FLAT_BASE_ADDR,
+ rdev->gart.table_addr);
+ WREG32_MC(R_00011C_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR, 0);
/* enable page tables */
- tmp = RREG32_MC(RS600_MC_PT0_CNTL);
- WREG32_MC(RS600_MC_PT0_CNTL, (tmp | RS600_ENABLE_PT));
- tmp = RREG32_MC(RS600_MC_CNTL1);
- WREG32_MC(RS600_MC_CNTL1, (tmp | RS600_ENABLE_PAGE_TABLES));
+ tmp = RREG32_MC(R_000100_MC_PT0_CNTL);
+ WREG32_MC(R_000100_MC_PT0_CNTL, (tmp | S_000100_ENABLE_PT(1)));
+ tmp = RREG32_MC(R_000009_MC_CNTL1);
+ WREG32_MC(R_000009_MC_CNTL1, (tmp | S_000009_ENABLE_PAGE_TABLES(1)));
rs600_gart_tlb_flush(rdev);
rdev->gart.ready = true;
return 0;
@@ -146,10 +149,9 @@ void rs600_gart_disable(struct radeon_device *rdev)
uint32_t tmp;
/* FIXME: disable out of gart access */
- WREG32_MC(RS600_MC_PT0_CNTL, 0);
- tmp = RREG32_MC(RS600_MC_CNTL1);
- tmp &= ~RS600_ENABLE_PAGE_TABLES;
- WREG32_MC(RS600_MC_CNTL1, tmp);
+ WREG32_MC(R_000100_MC_PT0_CNTL, 0);
+ tmp = RREG32_MC(R_000009_MC_CNTL1);
+ WREG32_MC(R_000009_MC_CNTL1, tmp & C_000009_ENABLE_PAGE_TABLES);
if (rdev->gart.table.vram.robj) {
radeon_object_kunmap(rdev->gart.table.vram.robj);
radeon_object_unpin(rdev->gart.table.vram.robj);
@@ -183,129 +185,61 @@ int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr)
return 0;
}
-
-/*
- * MC.
- */
-void rs600_mc_disable_clients(struct radeon_device *rdev)
-{
- unsigned tmp;
-
- if (r100_gui_wait_for_idle(rdev)) {
- printk(KERN_WARNING "Failed to wait GUI idle while "
- "programming pipes. Bad things might happen.\n");
- }
-
- rv515_vga_render_disable(rdev);
-
- tmp = RREG32(AVIVO_D1VGA_CONTROL);
- WREG32(AVIVO_D1VGA_CONTROL, tmp & ~AVIVO_DVGA_CONTROL_MODE_ENABLE);
- tmp = RREG32(AVIVO_D2VGA_CONTROL);
- WREG32(AVIVO_D2VGA_CONTROL, tmp & ~AVIVO_DVGA_CONTROL_MODE_ENABLE);
-
- tmp = RREG32(AVIVO_D1CRTC_CONTROL);
- WREG32(AVIVO_D1CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN);
- tmp = RREG32(AVIVO_D2CRTC_CONTROL);
- WREG32(AVIVO_D2CRTC_CONTROL, tmp & ~AVIVO_CRTC_EN);
-
- /* make sure all previous write got through */
- tmp = RREG32(AVIVO_D2CRTC_CONTROL);
-
- mdelay(1);
-}
-
-int rs600_mc_init(struct radeon_device *rdev)
-{
- uint32_t tmp;
- int r;
-
- if (r100_debugfs_rbbm_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for RBBM !\n");
- }
-
- rs600_gpu_init(rdev);
- rs600_gart_disable(rdev);
-
- /* Setup GPU memory space */
- rdev->mc.vram_location = 0xFFFFFFFFUL;
- rdev->mc.gtt_location = 0xFFFFFFFFUL;
- r = radeon_mc_setup(rdev);
- if (r) {
- return r;
- }
-
- /* Program GPU memory space */
- /* Enable bus master */
- tmp = RREG32(RADEON_BUS_CNTL) & ~RS600_BUS_MASTER_DIS;
- WREG32(RADEON_BUS_CNTL, tmp);
- /* FIXME: What does AGP means for such chipset ? */
- WREG32_MC(RS600_MC_AGP_LOCATION, 0x0FFFFFFF);
- /* FIXME: are this AGP reg in indirect MC range ? */
- WREG32_MC(RS600_MC_AGP_BASE, 0);
- WREG32_MC(RS600_MC_AGP_BASE_2, 0);
- rs600_mc_disable_clients(rdev);
- if (rs600_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "Failed to wait MC idle while "
- "programming pipes. Bad things might happen.\n");
- }
- tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
- tmp = REG_SET(RS600_MC_FB_TOP, tmp >> 16);
- tmp |= REG_SET(RS600_MC_FB_START, rdev->mc.vram_location >> 16);
- WREG32_MC(RS600_MC_FB_LOCATION, tmp);
- WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16);
- return 0;
-}
-
-void rs600_mc_fini(struct radeon_device *rdev)
-{
-}
-
-
-/*
- * Interrupts
- */
int rs600_irq_set(struct radeon_device *rdev)
{
uint32_t tmp = 0;
uint32_t mode_int = 0;
if (rdev->irq.sw_int) {
- tmp |= RADEON_SW_INT_ENABLE;
+ tmp |= S_000040_SW_INT_EN(1);
}
if (rdev->irq.crtc_vblank_int[0]) {
- mode_int |= AVIVO_D1MODE_INT_MASK;
+ mode_int |= S_006540_D1MODE_VBLANK_INT_MASK(1);
}
if (rdev->irq.crtc_vblank_int[1]) {
- mode_int |= AVIVO_D2MODE_INT_MASK;
+ mode_int |= S_006540_D2MODE_VBLANK_INT_MASK(1);
}
- WREG32(RADEON_GEN_INT_CNTL, tmp);
- WREG32(AVIVO_DxMODE_INT_MASK, mode_int);
+ WREG32(R_000040_GEN_INT_CNTL, tmp);
+ WREG32(R_006540_DxMODE_INT_MASK, mode_int);
return 0;
}
static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_int)
{
- uint32_t irqs = RREG32(RADEON_GEN_INT_STATUS);
- uint32_t irq_mask = RADEON_SW_INT_TEST;
-
- if (irqs & AVIVO_DISPLAY_INT_STATUS) {
- *r500_disp_int = RREG32(AVIVO_DISP_INTERRUPT_STATUS);
- if (*r500_disp_int & AVIVO_D1_VBLANK_INTERRUPT) {
- WREG32(AVIVO_D1MODE_VBLANK_STATUS, AVIVO_VBLANK_ACK);
+ uint32_t irqs = RREG32(R_000044_GEN_INT_STATUS);
+ uint32_t irq_mask = ~C_000044_SW_INT;
+
+ if (G_000044_DISPLAY_INT_STAT(irqs)) {
+ *r500_disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS);
+ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(*r500_disp_int)) {
+ WREG32(R_006534_D1MODE_VBLANK_STATUS,
+ S_006534_D1MODE_VBLANK_ACK(1));
}
- if (*r500_disp_int & AVIVO_D2_VBLANK_INTERRUPT) {
- WREG32(AVIVO_D2MODE_VBLANK_STATUS, AVIVO_VBLANK_ACK);
+ if (G_007EDC_LB_D2_VBLANK_INTERRUPT(*r500_disp_int)) {
+ WREG32(R_006D34_D2MODE_VBLANK_STATUS,
+ S_006D34_D2MODE_VBLANK_ACK(1));
}
} else {
*r500_disp_int = 0;
}
if (irqs) {
- WREG32(RADEON_GEN_INT_STATUS, irqs);
+ WREG32(R_000044_GEN_INT_STATUS, irqs);
}
return irqs & irq_mask;
}
+void rs600_irq_disable(struct radeon_device *rdev)
+{
+ u32 tmp;
+
+ WREG32(R_000040_GEN_INT_CNTL, 0);
+ WREG32(R_006540_DxMODE_INT_MASK, 0);
+ /* Wait and acknowledge irq */
+ mdelay(1);
+ rs600_irq_ack(rdev, &tmp);
+}
+
int rs600_irq_process(struct radeon_device *rdev)
{
uint32_t status;
@@ -317,16 +251,13 @@ int rs600_irq_process(struct radeon_device *rdev)
}
while (status || r500_disp_int) {
/* SW interrupt */
- if (status & RADEON_SW_INT_TEST) {
+ if (G_000040_SW_INT_EN(status))
radeon_fence_process(rdev);
- }
/* Vertical blank interrupts */
- if (r500_disp_int & AVIVO_D1_VBLANK_INTERRUPT) {
+ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int))
drm_handle_vblank(rdev->ddev, 0);
- }
- if (r500_disp_int & AVIVO_D2_VBLANK_INTERRUPT) {
+ if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int))
drm_handle_vblank(rdev->ddev, 1);
- }
status = rs600_irq_ack(rdev, &r500_disp_int);
}
return IRQ_HANDLED;
@@ -335,53 +266,34 @@ int rs600_irq_process(struct radeon_device *rdev)
u32 rs600_get_vblank_counter(struct radeon_device *rdev, int crtc)
{
if (crtc == 0)
- return RREG32(AVIVO_D1CRTC_FRAME_COUNT);
+ return RREG32(R_0060A4_D1CRTC_STATUS_FRAME_COUNT);
else
- return RREG32(AVIVO_D2CRTC_FRAME_COUNT);
+ return RREG32(R_0068A4_D2CRTC_STATUS_FRAME_COUNT);
}
-
-/*
- * Global GPU functions
- */
int rs600_mc_wait_for_idle(struct radeon_device *rdev)
{
unsigned i;
- uint32_t tmp;
for (i = 0; i < rdev->usec_timeout; i++) {
- /* read MC_STATUS */
- tmp = RREG32_MC(RS600_MC_STATUS);
- if (tmp & RS600_MC_STATUS_IDLE) {
+ if (G_000000_MC_IDLE(RREG32_MC(R_000000_MC_STATUS)))
return 0;
- }
- DRM_UDELAY(1);
+ udelay(1);
}
return -1;
}
-void rs600_errata(struct radeon_device *rdev)
-{
- rdev->pll_errata = 0;
-}
-
void rs600_gpu_init(struct radeon_device *rdev)
{
/* FIXME: HDP same place on rs600 ? */
r100_hdp_reset(rdev);
- rv515_vga_render_disable(rdev);
/* FIXME: is this correct ? */
r420_pipes_init(rdev);
- if (rs600_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "Failed to wait MC idle while "
- "programming pipes. Bad things might happen.\n");
- }
+ /* Wait for mc idle */
+ if (rs600_mc_wait_for_idle(rdev))
+ dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n");
}
-
-/*
- * VRAM info.
- */
void rs600_vram_info(struct radeon_device *rdev)
{
/* FIXME: to do or is these values sane ? */
@@ -394,31 +306,206 @@ void rs600_bandwidth_update(struct radeon_device *rdev)
/* FIXME: implement, should this be like rs690 ? */
}
-
-/*
- * Indirect registers accessor
- */
uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg)
{
- uint32_t r;
-
- WREG32(RS600_MC_INDEX,
- ((reg & RS600_MC_ADDR_MASK) | RS600_MC_IND_CITF_ARB0));
- r = RREG32(RS600_MC_DATA);
- return r;
+ WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) |
+ S_000070_MC_IND_CITF_ARB0(1));
+ return RREG32(R_000074_MC_IND_DATA);
}
void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
{
- WREG32(RS600_MC_INDEX,
- RS600_MC_IND_WR_EN | RS600_MC_IND_CITF_ARB0 |
- ((reg) & RS600_MC_ADDR_MASK));
- WREG32(RS600_MC_DATA, v);
+ WREG32(R_000070_MC_IND_INDEX, S_000070_MC_IND_ADDR(reg) |
+ S_000070_MC_IND_CITF_ARB0(1) | S_000070_MC_IND_WR_EN(1));
+ WREG32(R_000074_MC_IND_DATA, v);
}
-int rs600_init(struct radeon_device *rdev)
+void rs600_debugfs(struct radeon_device *rdev)
+{
+ if (r100_debugfs_rbbm_init(rdev))
+ DRM_ERROR("Failed to register debugfs file for RBBM !\n");
+}
+
+void rs600_set_safe_registers(struct radeon_device *rdev)
{
rdev->config.r300.reg_safe_bm = rs600_reg_safe_bm;
rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(rs600_reg_safe_bm);
+}
+
+static void rs600_mc_program(struct radeon_device *rdev)
+{
+ struct rv515_mc_save save;
+
+ /* Stops all mc clients */
+ rv515_mc_stop(rdev, &save);
+
+ /* Wait for mc idle */
+ if (rs600_mc_wait_for_idle(rdev))
+ dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n");
+
+ /* FIXME: What does AGP means for such chipset ? */
+ WREG32_MC(R_000005_MC_AGP_LOCATION, 0x0FFFFFFF);
+ WREG32_MC(R_000006_AGP_BASE, 0);
+ WREG32_MC(R_000007_AGP_BASE_2, 0);
+ /* Program MC */
+ WREG32_MC(R_000004_MC_FB_LOCATION,
+ S_000004_MC_FB_START(rdev->mc.vram_start >> 16) |
+ S_000004_MC_FB_TOP(rdev->mc.vram_end >> 16));
+ WREG32(R_000134_HDP_FB_LOCATION,
+ S_000134_HDP_FB_START(rdev->mc.vram_start >> 16));
+
+ rv515_mc_resume(rdev, &save);
+}
+
+static int rs600_startup(struct radeon_device *rdev)
+{
+ int r;
+
+ rs600_mc_program(rdev);
+ /* Resume clock */
+ rv515_clock_startup(rdev);
+ /* Initialize GPU configuration (# pipes, ...) */
+ rs600_gpu_init(rdev);
+ /* Initialize GART (initialize after TTM so we can allocate
+ * memory through TTM but finalize after TTM) */
+ r = rs600_gart_enable(rdev);
+ if (r)
+ return r;
+ /* Enable IRQ */
+ rdev->irq.sw_int = true;
+ rs600_irq_set(rdev);
+ /* 1M ring buffer */
+ r = r100_cp_init(rdev, 1024 * 1024);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ return r;
+ }
+ r = r100_wb_init(rdev);
+ if (r)
+ dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
+ r = r100_ib_init(rdev);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ return r;
+ }
+ return 0;
+}
+
+int rs600_resume(struct radeon_device *rdev)
+{
+ /* Make sur GART are not working */
+ rs600_gart_disable(rdev);
+ /* Resume clock before doing reset */
+ rv515_clock_startup(rdev);
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_reset(rdev)) {
+ dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
+ RREG32(R_000E40_RBBM_STATUS),
+ RREG32(R_0007C0_CP_STAT));
+ }
+ /* post */
+ atom_asic_init(rdev->mode_info.atom_context);
+ /* Resume clock after posting */
+ rv515_clock_startup(rdev);
+ return rs600_startup(rdev);
+}
+
+int rs600_suspend(struct radeon_device *rdev)
+{
+ r100_cp_disable(rdev);
+ r100_wb_disable(rdev);
+ rs600_irq_disable(rdev);
+ rs600_gart_disable(rdev);
+ return 0;
+}
+
+void rs600_fini(struct radeon_device *rdev)
+{
+ rs600_suspend(rdev);
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ radeon_gem_fini(rdev);
+ rs600_gart_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ radeon_fence_driver_fini(rdev);
+ radeon_object_fini(rdev);
+ radeon_atombios_fini(rdev);
+ kfree(rdev->bios);
+ rdev->bios = NULL;
+}
+
+int rs600_init(struct radeon_device *rdev)
+{
+ int r;
+
+ /* Disable VGA */
+ rv515_vga_render_disable(rdev);
+ /* Initialize scratch registers */
+ radeon_scratch_init(rdev);
+ /* Initialize surface registers */
+ radeon_surface_init(rdev);
+ /* BIOS */
+ if (!radeon_get_bios(rdev)) {
+ if (ASIC_IS_AVIVO(rdev))
+ return -EINVAL;
+ }
+ if (rdev->is_atom_bios) {
+ r = radeon_atombios_init(rdev);
+ if (r)
+ return r;
+ } else {
+ dev_err(rdev->dev, "Expecting atombios for RS600 GPU\n");
+ return -EINVAL;
+ }
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_reset(rdev)) {
+ dev_warn(rdev->dev,
+ "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
+ RREG32(R_000E40_RBBM_STATUS),
+ RREG32(R_0007C0_CP_STAT));
+ }
+ /* check if cards are posted or not */
+ if (!radeon_card_posted(rdev) && rdev->bios) {
+ DRM_INFO("GPU not posted. posting now...\n");
+ atom_asic_init(rdev->mode_info.atom_context);
+ }
+ /* Initialize clocks */
+ radeon_get_clock_info(rdev->ddev);
+ /* Get vram informations */
+ rs600_vram_info(rdev);
+ /* Initialize memory controller (also test AGP) */
+ r = r420_mc_init(rdev);
+ if (r)
+ return r;
+ rs600_debugfs(rdev);
+ /* Fence driver */
+ r = radeon_fence_driver_init(rdev);
+ if (r)
+ return r;
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ /* Memory manager */
+ r = radeon_object_init(rdev);
+ if (r)
+ return r;
+ r = rs600_gart_init(rdev);
+ if (r)
+ return r;
+ rs600_set_safe_registers(rdev);
+ rdev->accel_working = true;
+ r = rs600_startup(rdev);
+ if (r) {
+ /* Somethings want wront with the accel init stop accel */
+ dev_err(rdev->dev, "Disabling GPU acceleration\n");
+ rs600_suspend(rdev);
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ rs600_gart_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ rdev->accel_working = false;
+ }
return 0;
}
diff --git a/drivers/gpu/drm/radeon/rs600d.h b/drivers/gpu/drm/radeon/rs600d.h
new file mode 100644
index 000000000000..81308924859a
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs600d.h
@@ -0,0 +1,470 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#ifndef __RS600D_H__
+#define __RS600D_H__
+
+/* Registers */
+#define R_000040_GEN_INT_CNTL 0x000040
+#define S_000040_DISPLAY_INT_STATUS(x) (((x) & 0x1) << 0)
+#define G_000040_DISPLAY_INT_STATUS(x) (((x) >> 0) & 0x1)
+#define C_000040_DISPLAY_INT_STATUS 0xFFFFFFFE
+#define S_000040_DMA_VIPH0_INT_EN(x) (((x) & 0x1) << 12)
+#define G_000040_DMA_VIPH0_INT_EN(x) (((x) >> 12) & 0x1)
+#define C_000040_DMA_VIPH0_INT_EN 0xFFFFEFFF
+#define S_000040_CRTC2_VSYNC(x) (((x) & 0x1) << 6)
+#define G_000040_CRTC2_VSYNC(x) (((x) >> 6) & 0x1)
+#define C_000040_CRTC2_VSYNC 0xFFFFFFBF
+#define S_000040_SNAPSHOT2(x) (((x) & 0x1) << 7)
+#define G_000040_SNAPSHOT2(x) (((x) >> 7) & 0x1)
+#define C_000040_SNAPSHOT2 0xFFFFFF7F
+#define S_000040_CRTC2_VBLANK(x) (((x) & 0x1) << 9)
+#define G_000040_CRTC2_VBLANK(x) (((x) >> 9) & 0x1)
+#define C_000040_CRTC2_VBLANK 0xFFFFFDFF
+#define S_000040_FP2_DETECT(x) (((x) & 0x1) << 10)
+#define G_000040_FP2_DETECT(x) (((x) >> 10) & 0x1)
+#define C_000040_FP2_DETECT 0xFFFFFBFF
+#define S_000040_VSYNC_DIFF_OVER_LIMIT(x) (((x) & 0x1) << 11)
+#define G_000040_VSYNC_DIFF_OVER_LIMIT(x) (((x) >> 11) & 0x1)
+#define C_000040_VSYNC_DIFF_OVER_LIMIT 0xFFFFF7FF
+#define S_000040_DMA_VIPH1_INT_EN(x) (((x) & 0x1) << 13)
+#define G_000040_DMA_VIPH1_INT_EN(x) (((x) >> 13) & 0x1)
+#define C_000040_DMA_VIPH1_INT_EN 0xFFFFDFFF
+#define S_000040_DMA_VIPH2_INT_EN(x) (((x) & 0x1) << 14)
+#define G_000040_DMA_VIPH2_INT_EN(x) (((x) >> 14) & 0x1)
+#define C_000040_DMA_VIPH2_INT_EN 0xFFFFBFFF
+#define S_000040_DMA_VIPH3_INT_EN(x) (((x) & 0x1) << 15)
+#define G_000040_DMA_VIPH3_INT_EN(x) (((x) >> 15) & 0x1)
+#define C_000040_DMA_VIPH3_INT_EN 0xFFFF7FFF
+#define S_000040_I2C_INT_EN(x) (((x) & 0x1) << 17)
+#define G_000040_I2C_INT_EN(x) (((x) >> 17) & 0x1)
+#define C_000040_I2C_INT_EN 0xFFFDFFFF
+#define S_000040_GUI_IDLE(x) (((x) & 0x1) << 19)
+#define G_000040_GUI_IDLE(x) (((x) >> 19) & 0x1)
+#define C_000040_GUI_IDLE 0xFFF7FFFF
+#define S_000040_VIPH_INT_EN(x) (((x) & 0x1) << 24)
+#define G_000040_VIPH_INT_EN(x) (((x) >> 24) & 0x1)
+#define C_000040_VIPH_INT_EN 0xFEFFFFFF
+#define S_000040_SW_INT_EN(x) (((x) & 0x1) << 25)
+#define G_000040_SW_INT_EN(x) (((x) >> 25) & 0x1)
+#define C_000040_SW_INT_EN 0xFDFFFFFF
+#define S_000040_GEYSERVILLE(x) (((x) & 0x1) << 27)
+#define G_000040_GEYSERVILLE(x) (((x) >> 27) & 0x1)
+#define C_000040_GEYSERVILLE 0xF7FFFFFF
+#define S_000040_HDCP_AUTHORIZED_INT(x) (((x) & 0x1) << 28)
+#define G_000040_HDCP_AUTHORIZED_INT(x) (((x) >> 28) & 0x1)
+#define C_000040_HDCP_AUTHORIZED_INT 0xEFFFFFFF
+#define S_000040_DVI_I2C_INT(x) (((x) & 0x1) << 29)
+#define G_000040_DVI_I2C_INT(x) (((x) >> 29) & 0x1)
+#define C_000040_DVI_I2C_INT 0xDFFFFFFF
+#define S_000040_GUIDMA(x) (((x) & 0x1) << 30)
+#define G_000040_GUIDMA(x) (((x) >> 30) & 0x1)
+#define C_000040_GUIDMA 0xBFFFFFFF
+#define S_000040_VIDDMA(x) (((x) & 0x1) << 31)
+#define G_000040_VIDDMA(x) (((x) >> 31) & 0x1)
+#define C_000040_VIDDMA 0x7FFFFFFF
+#define R_000044_GEN_INT_STATUS 0x000044
+#define S_000044_DISPLAY_INT_STAT(x) (((x) & 0x1) << 0)
+#define G_000044_DISPLAY_INT_STAT(x) (((x) >> 0) & 0x1)
+#define C_000044_DISPLAY_INT_STAT 0xFFFFFFFE
+#define S_000044_VGA_INT_STAT(x) (((x) & 0x1) << 1)
+#define G_000044_VGA_INT_STAT(x) (((x) >> 1) & 0x1)
+#define C_000044_VGA_INT_STAT 0xFFFFFFFD
+#define S_000044_CAP0_INT_ACTIVE(x) (((x) & 0x1) << 8)
+#define G_000044_CAP0_INT_ACTIVE(x) (((x) >> 8) & 0x1)
+#define C_000044_CAP0_INT_ACTIVE 0xFFFFFEFF
+#define S_000044_DMA_VIPH0_INT(x) (((x) & 0x1) << 12)
+#define G_000044_DMA_VIPH0_INT(x) (((x) >> 12) & 0x1)
+#define C_000044_DMA_VIPH0_INT 0xFFFFEFFF
+#define S_000044_DMA_VIPH1_INT(x) (((x) & 0x1) << 13)
+#define G_000044_DMA_VIPH1_INT(x) (((x) >> 13) & 0x1)
+#define C_000044_DMA_VIPH1_INT 0xFFFFDFFF
+#define S_000044_DMA_VIPH2_INT(x) (((x) & 0x1) << 14)
+#define G_000044_DMA_VIPH2_INT(x) (((x) >> 14) & 0x1)
+#define C_000044_DMA_VIPH2_INT 0xFFFFBFFF
+#define S_000044_DMA_VIPH3_INT(x) (((x) & 0x1) << 15)
+#define G_000044_DMA_VIPH3_INT(x) (((x) >> 15) & 0x1)
+#define C_000044_DMA_VIPH3_INT 0xFFFF7FFF
+#define S_000044_MC_PROBE_FAULT_STAT(x) (((x) & 0x1) << 16)
+#define G_000044_MC_PROBE_FAULT_STAT(x) (((x) >> 16) & 0x1)
+#define C_000044_MC_PROBE_FAULT_STAT 0xFFFEFFFF
+#define S_000044_I2C_INT(x) (((x) & 0x1) << 17)
+#define G_000044_I2C_INT(x) (((x) >> 17) & 0x1)
+#define C_000044_I2C_INT 0xFFFDFFFF
+#define S_000044_SCRATCH_INT_STAT(x) (((x) & 0x1) << 18)
+#define G_000044_SCRATCH_INT_STAT(x) (((x) >> 18) & 0x1)
+#define C_000044_SCRATCH_INT_STAT 0xFFFBFFFF
+#define S_000044_GUI_IDLE_STAT(x) (((x) & 0x1) << 19)
+#define G_000044_GUI_IDLE_STAT(x) (((x) >> 19) & 0x1)
+#define C_000044_GUI_IDLE_STAT 0xFFF7FFFF
+#define S_000044_ATI_OVERDRIVE_INT_STAT(x) (((x) & 0x1) << 20)
+#define G_000044_ATI_OVERDRIVE_INT_STAT(x) (((x) >> 20) & 0x1)
+#define C_000044_ATI_OVERDRIVE_INT_STAT 0xFFEFFFFF
+#define S_000044_MC_PROTECTION_FAULT_STAT(x) (((x) & 0x1) << 21)
+#define G_000044_MC_PROTECTION_FAULT_STAT(x) (((x) >> 21) & 0x1)
+#define C_000044_MC_PROTECTION_FAULT_STAT 0xFFDFFFFF
+#define S_000044_RBBM_READ_INT_STAT(x) (((x) & 0x1) << 22)
+#define G_000044_RBBM_READ_INT_STAT(x) (((x) >> 22) & 0x1)
+#define C_000044_RBBM_READ_INT_STAT 0xFFBFFFFF
+#define S_000044_CB_CONTEXT_SWITCH_STAT(x) (((x) & 0x1) << 23)
+#define G_000044_CB_CONTEXT_SWITCH_STAT(x) (((x) >> 23) & 0x1)
+#define C_000044_CB_CONTEXT_SWITCH_STAT 0xFF7FFFFF
+#define S_000044_VIPH_INT(x) (((x) & 0x1) << 24)
+#define G_000044_VIPH_INT(x) (((x) >> 24) & 0x1)
+#define C_000044_VIPH_INT 0xFEFFFFFF
+#define S_000044_SW_INT(x) (((x) & 0x1) << 25)
+#define G_000044_SW_INT(x) (((x) >> 25) & 0x1)
+#define C_000044_SW_INT 0xFDFFFFFF
+#define S_000044_SW_INT_SET(x) (((x) & 0x1) << 26)
+#define G_000044_SW_INT_SET(x) (((x) >> 26) & 0x1)
+#define C_000044_SW_INT_SET 0xFBFFFFFF
+#define S_000044_IDCT_INT_STAT(x) (((x) & 0x1) << 27)
+#define G_000044_IDCT_INT_STAT(x) (((x) >> 27) & 0x1)
+#define C_000044_IDCT_INT_STAT 0xF7FFFFFF
+#define S_000044_GUIDMA_STAT(x) (((x) & 0x1) << 30)
+#define G_000044_GUIDMA_STAT(x) (((x) >> 30) & 0x1)
+#define C_000044_GUIDMA_STAT 0xBFFFFFFF
+#define S_000044_VIDDMA_STAT(x) (((x) & 0x1) << 31)
+#define G_000044_VIDDMA_STAT(x) (((x) >> 31) & 0x1)
+#define C_000044_VIDDMA_STAT 0x7FFFFFFF
+#define R_00004C_BUS_CNTL 0x00004C
+#define S_00004C_BUS_MASTER_DIS(x) (((x) & 0x1) << 14)
+#define G_00004C_BUS_MASTER_DIS(x) (((x) >> 14) & 0x1)
+#define C_00004C_BUS_MASTER_DIS 0xFFFFBFFF
+#define S_00004C_BUS_MSI_REARM(x) (((x) & 0x1) << 20)
+#define G_00004C_BUS_MSI_REARM(x) (((x) >> 20) & 0x1)
+#define C_00004C_BUS_MSI_REARM 0xFFEFFFFF
+#define R_000070_MC_IND_INDEX 0x000070
+#define S_000070_MC_IND_ADDR(x) (((x) & 0xFFFF) << 0)
+#define G_000070_MC_IND_ADDR(x) (((x) >> 0) & 0xFFFF)
+#define C_000070_MC_IND_ADDR 0xFFFF0000
+#define S_000070_MC_IND_SEQ_RBS_0(x) (((x) & 0x1) << 16)
+#define G_000070_MC_IND_SEQ_RBS_0(x) (((x) >> 16) & 0x1)
+#define C_000070_MC_IND_SEQ_RBS_0 0xFFFEFFFF
+#define S_000070_MC_IND_SEQ_RBS_1(x) (((x) & 0x1) << 17)
+#define G_000070_MC_IND_SEQ_RBS_1(x) (((x) >> 17) & 0x1)
+#define C_000070_MC_IND_SEQ_RBS_1 0xFFFDFFFF
+#define S_000070_MC_IND_SEQ_RBS_2(x) (((x) & 0x1) << 18)
+#define G_000070_MC_IND_SEQ_RBS_2(x) (((x) >> 18) & 0x1)
+#define C_000070_MC_IND_SEQ_RBS_2 0xFFFBFFFF
+#define S_000070_MC_IND_SEQ_RBS_3(x) (((x) & 0x1) << 19)
+#define G_000070_MC_IND_SEQ_RBS_3(x) (((x) >> 19) & 0x1)
+#define C_000070_MC_IND_SEQ_RBS_3 0xFFF7FFFF
+#define S_000070_MC_IND_AIC_RBS(x) (((x) & 0x1) << 20)
+#define G_000070_MC_IND_AIC_RBS(x) (((x) >> 20) & 0x1)
+#define C_000070_MC_IND_AIC_RBS 0xFFEFFFFF
+#define S_000070_MC_IND_CITF_ARB0(x) (((x) & 0x1) << 21)
+#define G_000070_MC_IND_CITF_ARB0(x) (((x) >> 21) & 0x1)
+#define C_000070_MC_IND_CITF_ARB0 0xFFDFFFFF
+#define S_000070_MC_IND_CITF_ARB1(x) (((x) & 0x1) << 22)
+#define G_000070_MC_IND_CITF_ARB1(x) (((x) >> 22) & 0x1)
+#define C_000070_MC_IND_CITF_ARB1 0xFFBFFFFF
+#define S_000070_MC_IND_WR_EN(x) (((x) & 0x1) << 23)
+#define G_000070_MC_IND_WR_EN(x) (((x) >> 23) & 0x1)
+#define C_000070_MC_IND_WR_EN 0xFF7FFFFF
+#define S_000070_MC_IND_RD_INV(x) (((x) & 0x1) << 24)
+#define G_000070_MC_IND_RD_INV(x) (((x) >> 24) & 0x1)
+#define C_000070_MC_IND_RD_INV 0xFEFFFFFF
+#define R_000074_MC_IND_DATA 0x000074
+#define S_000074_MC_IND_DATA(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_000074_MC_IND_DATA(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_000074_MC_IND_DATA 0x00000000
+#define R_000134_HDP_FB_LOCATION 0x000134
+#define S_000134_HDP_FB_START(x) (((x) & 0xFFFF) << 0)
+#define G_000134_HDP_FB_START(x) (((x) >> 0) & 0xFFFF)
+#define C_000134_HDP_FB_START 0xFFFF0000
+#define R_0007C0_CP_STAT 0x0007C0
+#define S_0007C0_MRU_BUSY(x) (((x) & 0x1) << 0)
+#define G_0007C0_MRU_BUSY(x) (((x) >> 0) & 0x1)
+#define C_0007C0_MRU_BUSY 0xFFFFFFFE
+#define S_0007C0_MWU_BUSY(x) (((x) & 0x1) << 1)
+#define G_0007C0_MWU_BUSY(x) (((x) >> 1) & 0x1)
+#define C_0007C0_MWU_BUSY 0xFFFFFFFD
+#define S_0007C0_RSIU_BUSY(x) (((x) & 0x1) << 2)
+#define G_0007C0_RSIU_BUSY(x) (((x) >> 2) & 0x1)
+#define C_0007C0_RSIU_BUSY 0xFFFFFFFB
+#define S_0007C0_RCIU_BUSY(x) (((x) & 0x1) << 3)
+#define G_0007C0_RCIU_BUSY(x) (((x) >> 3) & 0x1)
+#define C_0007C0_RCIU_BUSY 0xFFFFFFF7
+#define S_0007C0_CSF_PRIMARY_BUSY(x) (((x) & 0x1) << 9)
+#define G_0007C0_CSF_PRIMARY_BUSY(x) (((x) >> 9) & 0x1)
+#define C_0007C0_CSF_PRIMARY_BUSY 0xFFFFFDFF
+#define S_0007C0_CSF_INDIRECT_BUSY(x) (((x) & 0x1) << 10)
+#define G_0007C0_CSF_INDIRECT_BUSY(x) (((x) >> 10) & 0x1)
+#define C_0007C0_CSF_INDIRECT_BUSY 0xFFFFFBFF
+#define S_0007C0_CSQ_PRIMARY_BUSY(x) (((x) & 0x1) << 11)
+#define G_0007C0_CSQ_PRIMARY_BUSY(x) (((x) >> 11) & 0x1)
+#define C_0007C0_CSQ_PRIMARY_BUSY 0xFFFFF7FF
+#define S_0007C0_CSQ_INDIRECT_BUSY(x) (((x) & 0x1) << 12)
+#define G_0007C0_CSQ_INDIRECT_BUSY(x) (((x) >> 12) & 0x1)
+#define C_0007C0_CSQ_INDIRECT_BUSY 0xFFFFEFFF
+#define S_0007C0_CSI_BUSY(x) (((x) & 0x1) << 13)
+#define G_0007C0_CSI_BUSY(x) (((x) >> 13) & 0x1)
+#define C_0007C0_CSI_BUSY 0xFFFFDFFF
+#define S_0007C0_CSF_INDIRECT2_BUSY(x) (((x) & 0x1) << 14)
+#define G_0007C0_CSF_INDIRECT2_BUSY(x) (((x) >> 14) & 0x1)
+#define C_0007C0_CSF_INDIRECT2_BUSY 0xFFFFBFFF
+#define S_0007C0_CSQ_INDIRECT2_BUSY(x) (((x) & 0x1) << 15)
+#define G_0007C0_CSQ_INDIRECT2_BUSY(x) (((x) >> 15) & 0x1)
+#define C_0007C0_CSQ_INDIRECT2_BUSY 0xFFFF7FFF
+#define S_0007C0_GUIDMA_BUSY(x) (((x) & 0x1) << 28)
+#define G_0007C0_GUIDMA_BUSY(x) (((x) >> 28) & 0x1)
+#define C_0007C0_GUIDMA_BUSY 0xEFFFFFFF
+#define S_0007C0_VIDDMA_BUSY(x) (((x) & 0x1) << 29)
+#define G_0007C0_VIDDMA_BUSY(x) (((x) >> 29) & 0x1)
+#define C_0007C0_VIDDMA_BUSY 0xDFFFFFFF
+#define S_0007C0_CMDSTRM_BUSY(x) (((x) & 0x1) << 30)
+#define G_0007C0_CMDSTRM_BUSY(x) (((x) >> 30) & 0x1)
+#define C_0007C0_CMDSTRM_BUSY 0xBFFFFFFF
+#define S_0007C0_CP_BUSY(x) (((x) & 0x1) << 31)
+#define G_0007C0_CP_BUSY(x) (((x) >> 31) & 0x1)
+#define C_0007C0_CP_BUSY 0x7FFFFFFF
+#define R_000E40_RBBM_STATUS 0x000E40
+#define S_000E40_CMDFIFO_AVAIL(x) (((x) & 0x7F) << 0)
+#define G_000E40_CMDFIFO_AVAIL(x) (((x) >> 0) & 0x7F)
+#define C_000E40_CMDFIFO_AVAIL 0xFFFFFF80
+#define S_000E40_HIRQ_ON_RBB(x) (((x) & 0x1) << 8)
+#define G_000E40_HIRQ_ON_RBB(x) (((x) >> 8) & 0x1)
+#define C_000E40_HIRQ_ON_RBB 0xFFFFFEFF
+#define S_000E40_CPRQ_ON_RBB(x) (((x) & 0x1) << 9)
+#define G_000E40_CPRQ_ON_RBB(x) (((x) >> 9) & 0x1)
+#define C_000E40_CPRQ_ON_RBB 0xFFFFFDFF
+#define S_000E40_CFRQ_ON_RBB(x) (((x) & 0x1) << 10)
+#define G_000E40_CFRQ_ON_RBB(x) (((x) >> 10) & 0x1)
+#define C_000E40_CFRQ_ON_RBB 0xFFFFFBFF
+#define S_000E40_HIRQ_IN_RTBUF(x) (((x) & 0x1) << 11)
+#define G_000E40_HIRQ_IN_RTBUF(x) (((x) >> 11) & 0x1)
+#define C_000E40_HIRQ_IN_RTBUF 0xFFFFF7FF
+#define S_000E40_CPRQ_IN_RTBUF(x) (((x) & 0x1) << 12)
+#define G_000E40_CPRQ_IN_RTBUF(x) (((x) >> 12) & 0x1)
+#define C_000E40_CPRQ_IN_RTBUF 0xFFFFEFFF
+#define S_000E40_CFRQ_IN_RTBUF(x) (((x) & 0x1) << 13)
+#define G_000E40_CFRQ_IN_RTBUF(x) (((x) >> 13) & 0x1)
+#define C_000E40_CFRQ_IN_RTBUF 0xFFFFDFFF
+#define S_000E40_CF_PIPE_BUSY(x) (((x) & 0x1) << 14)
+#define G_000E40_CF_PIPE_BUSY(x) (((x) >> 14) & 0x1)
+#define C_000E40_CF_PIPE_BUSY 0xFFFFBFFF
+#define S_000E40_ENG_EV_BUSY(x) (((x) & 0x1) << 15)
+#define G_000E40_ENG_EV_BUSY(x) (((x) >> 15) & 0x1)
+#define C_000E40_ENG_EV_BUSY 0xFFFF7FFF
+#define S_000E40_CP_CMDSTRM_BUSY(x) (((x) & 0x1) << 16)
+#define G_000E40_CP_CMDSTRM_BUSY(x) (((x) >> 16) & 0x1)
+#define C_000E40_CP_CMDSTRM_BUSY 0xFFFEFFFF
+#define S_000E40_E2_BUSY(x) (((x) & 0x1) << 17)
+#define G_000E40_E2_BUSY(x) (((x) >> 17) & 0x1)
+#define C_000E40_E2_BUSY 0xFFFDFFFF
+#define S_000E40_RB2D_BUSY(x) (((x) & 0x1) << 18)
+#define G_000E40_RB2D_BUSY(x) (((x) >> 18) & 0x1)
+#define C_000E40_RB2D_BUSY 0xFFFBFFFF
+#define S_000E40_RB3D_BUSY(x) (((x) & 0x1) << 19)
+#define G_000E40_RB3D_BUSY(x) (((x) >> 19) & 0x1)
+#define C_000E40_RB3D_BUSY 0xFFF7FFFF
+#define S_000E40_VAP_BUSY(x) (((x) & 0x1) << 20)
+#define G_000E40_VAP_BUSY(x) (((x) >> 20) & 0x1)
+#define C_000E40_VAP_BUSY 0xFFEFFFFF
+#define S_000E40_RE_BUSY(x) (((x) & 0x1) << 21)
+#define G_000E40_RE_BUSY(x) (((x) >> 21) & 0x1)
+#define C_000E40_RE_BUSY 0xFFDFFFFF
+#define S_000E40_TAM_BUSY(x) (((x) & 0x1) << 22)
+#define G_000E40_TAM_BUSY(x) (((x) >> 22) & 0x1)
+#define C_000E40_TAM_BUSY 0xFFBFFFFF
+#define S_000E40_TDM_BUSY(x) (((x) & 0x1) << 23)
+#define G_000E40_TDM_BUSY(x) (((x) >> 23) & 0x1)
+#define C_000E40_TDM_BUSY 0xFF7FFFFF
+#define S_000E40_PB_BUSY(x) (((x) & 0x1) << 24)
+#define G_000E40_PB_BUSY(x) (((x) >> 24) & 0x1)
+#define C_000E40_PB_BUSY 0xFEFFFFFF
+#define S_000E40_TIM_BUSY(x) (((x) & 0x1) << 25)
+#define G_000E40_TIM_BUSY(x) (((x) >> 25) & 0x1)
+#define C_000E40_TIM_BUSY 0xFDFFFFFF
+#define S_000E40_GA_BUSY(x) (((x) & 0x1) << 26)
+#define G_000E40_GA_BUSY(x) (((x) >> 26) & 0x1)
+#define C_000E40_GA_BUSY 0xFBFFFFFF
+#define S_000E40_CBA2D_BUSY(x) (((x) & 0x1) << 27)
+#define G_000E40_CBA2D_BUSY(x) (((x) >> 27) & 0x1)
+#define C_000E40_CBA2D_BUSY 0xF7FFFFFF
+#define S_000E40_GUI_ACTIVE(x) (((x) & 0x1) << 31)
+#define G_000E40_GUI_ACTIVE(x) (((x) >> 31) & 0x1)
+#define C_000E40_GUI_ACTIVE 0x7FFFFFFF
+#define R_0060A4_D1CRTC_STATUS_FRAME_COUNT 0x0060A4
+#define S_0060A4_D1CRTC_FRAME_COUNT(x) (((x) & 0xFFFFFF) << 0)
+#define G_0060A4_D1CRTC_FRAME_COUNT(x) (((x) >> 0) & 0xFFFFFF)
+#define C_0060A4_D1CRTC_FRAME_COUNT 0xFF000000
+#define R_006534_D1MODE_VBLANK_STATUS 0x006534
+#define S_006534_D1MODE_VBLANK_OCCURRED(x) (((x) & 0x1) << 0)
+#define G_006534_D1MODE_VBLANK_OCCURRED(x) (((x) >> 0) & 0x1)
+#define C_006534_D1MODE_VBLANK_OCCURRED 0xFFFFFFFE
+#define S_006534_D1MODE_VBLANK_ACK(x) (((x) & 0x1) << 4)
+#define G_006534_D1MODE_VBLANK_ACK(x) (((x) >> 4) & 0x1)
+#define C_006534_D1MODE_VBLANK_ACK 0xFFFFFFEF
+#define S_006534_D1MODE_VBLANK_STAT(x) (((x) & 0x1) << 12)
+#define G_006534_D1MODE_VBLANK_STAT(x) (((x) >> 12) & 0x1)
+#define C_006534_D1MODE_VBLANK_STAT 0xFFFFEFFF
+#define S_006534_D1MODE_VBLANK_INTERRUPT(x) (((x) & 0x1) << 16)
+#define G_006534_D1MODE_VBLANK_INTERRUPT(x) (((x) >> 16) & 0x1)
+#define C_006534_D1MODE_VBLANK_INTERRUPT 0xFFFEFFFF
+#define R_006540_DxMODE_INT_MASK 0x006540
+#define S_006540_D1MODE_VBLANK_INT_MASK(x) (((x) & 0x1) << 0)
+#define G_006540_D1MODE_VBLANK_INT_MASK(x) (((x) >> 0) & 0x1)
+#define C_006540_D1MODE_VBLANK_INT_MASK 0xFFFFFFFE
+#define S_006540_D1MODE_VLINE_INT_MASK(x) (((x) & 0x1) << 4)
+#define G_006540_D1MODE_VLINE_INT_MASK(x) (((x) >> 4) & 0x1)
+#define C_006540_D1MODE_VLINE_INT_MASK 0xFFFFFFEF
+#define S_006540_D2MODE_VBLANK_INT_MASK(x) (((x) & 0x1) << 8)
+#define G_006540_D2MODE_VBLANK_INT_MASK(x) (((x) >> 8) & 0x1)
+#define C_006540_D2MODE_VBLANK_INT_MASK 0xFFFFFEFF
+#define S_006540_D2MODE_VLINE_INT_MASK(x) (((x) & 0x1) << 12)
+#define G_006540_D2MODE_VLINE_INT_MASK(x) (((x) >> 12) & 0x1)
+#define C_006540_D2MODE_VLINE_INT_MASK 0xFFFFEFFF
+#define S_006540_D1MODE_VBLANK_CP_SEL(x) (((x) & 0x1) << 30)
+#define G_006540_D1MODE_VBLANK_CP_SEL(x) (((x) >> 30) & 0x1)
+#define C_006540_D1MODE_VBLANK_CP_SEL 0xBFFFFFFF
+#define S_006540_D2MODE_VBLANK_CP_SEL(x) (((x) & 0x1) << 31)
+#define G_006540_D2MODE_VBLANK_CP_SEL(x) (((x) >> 31) & 0x1)
+#define C_006540_D2MODE_VBLANK_CP_SEL 0x7FFFFFFF
+#define R_0068A4_D2CRTC_STATUS_FRAME_COUNT 0x0068A4
+#define S_0068A4_D2CRTC_FRAME_COUNT(x) (((x) & 0xFFFFFF) << 0)
+#define G_0068A4_D2CRTC_FRAME_COUNT(x) (((x) >> 0) & 0xFFFFFF)
+#define C_0068A4_D2CRTC_FRAME_COUNT 0xFF000000
+#define R_006D34_D2MODE_VBLANK_STATUS 0x006D34
+#define S_006D34_D2MODE_VBLANK_OCCURRED(x) (((x) & 0x1) << 0)
+#define G_006D34_D2MODE_VBLANK_OCCURRED(x) (((x) >> 0) & 0x1)
+#define C_006D34_D2MODE_VBLANK_OCCURRED 0xFFFFFFFE
+#define S_006D34_D2MODE_VBLANK_ACK(x) (((x) & 0x1) << 4)
+#define G_006D34_D2MODE_VBLANK_ACK(x) (((x) >> 4) & 0x1)
+#define C_006D34_D2MODE_VBLANK_ACK 0xFFFFFFEF
+#define S_006D34_D2MODE_VBLANK_STAT(x) (((x) & 0x1) << 12)
+#define G_006D34_D2MODE_VBLANK_STAT(x) (((x) >> 12) & 0x1)
+#define C_006D34_D2MODE_VBLANK_STAT 0xFFFFEFFF
+#define S_006D34_D2MODE_VBLANK_INTERRUPT(x) (((x) & 0x1) << 16)
+#define G_006D34_D2MODE_VBLANK_INTERRUPT(x) (((x) >> 16) & 0x1)
+#define C_006D34_D2MODE_VBLANK_INTERRUPT 0xFFFEFFFF
+#define R_007EDC_DISP_INTERRUPT_STATUS 0x007EDC
+#define S_007EDC_LB_D1_VBLANK_INTERRUPT(x) (((x) & 0x1) << 4)
+#define G_007EDC_LB_D1_VBLANK_INTERRUPT(x) (((x) >> 4) & 0x1)
+#define C_007EDC_LB_D1_VBLANK_INTERRUPT 0xFFFFFFEF
+#define S_007EDC_LB_D2_VBLANK_INTERRUPT(x) (((x) & 0x1) << 5)
+#define G_007EDC_LB_D2_VBLANK_INTERRUPT(x) (((x) >> 5) & 0x1)
+#define C_007EDC_LB_D2_VBLANK_INTERRUPT 0xFFFFFFDF
+
+
+/* MC registers */
+#define R_000000_MC_STATUS 0x000000
+#define S_000000_MC_IDLE(x) (((x) & 0x1) << 0)
+#define G_000000_MC_IDLE(x) (((x) >> 0) & 0x1)
+#define C_000000_MC_IDLE 0xFFFFFFFE
+#define R_000004_MC_FB_LOCATION 0x000004
+#define S_000004_MC_FB_START(x) (((x) & 0xFFFF) << 0)
+#define G_000004_MC_FB_START(x) (((x) >> 0) & 0xFFFF)
+#define C_000004_MC_FB_START 0xFFFF0000
+#define S_000004_MC_FB_TOP(x) (((x) & 0xFFFF) << 16)
+#define G_000004_MC_FB_TOP(x) (((x) >> 16) & 0xFFFF)
+#define C_000004_MC_FB_TOP 0x0000FFFF
+#define R_000005_MC_AGP_LOCATION 0x000005
+#define S_000005_MC_AGP_START(x) (((x) & 0xFFFF) << 0)
+#define G_000005_MC_AGP_START(x) (((x) >> 0) & 0xFFFF)
+#define C_000005_MC_AGP_START 0xFFFF0000
+#define S_000005_MC_AGP_TOP(x) (((x) & 0xFFFF) << 16)
+#define G_000005_MC_AGP_TOP(x) (((x) >> 16) & 0xFFFF)
+#define C_000005_MC_AGP_TOP 0x0000FFFF
+#define R_000006_AGP_BASE 0x000006
+#define S_000006_AGP_BASE_ADDR(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_000006_AGP_BASE_ADDR(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_000006_AGP_BASE_ADDR 0x00000000
+#define R_000007_AGP_BASE_2 0x000007
+#define S_000007_AGP_BASE_ADDR_2(x) (((x) & 0xF) << 0)
+#define G_000007_AGP_BASE_ADDR_2(x) (((x) >> 0) & 0xF)
+#define C_000007_AGP_BASE_ADDR_2 0xFFFFFFF0
+#define R_000009_MC_CNTL1 0x000009
+#define S_000009_ENABLE_PAGE_TABLES(x) (((x) & 0x1) << 26)
+#define G_000009_ENABLE_PAGE_TABLES(x) (((x) >> 26) & 0x1)
+#define C_000009_ENABLE_PAGE_TABLES 0xFBFFFFFF
+/* FIXME don't know the various field size need feedback from AMD */
+#define R_000100_MC_PT0_CNTL 0x000100
+#define S_000100_ENABLE_PT(x) (((x) & 0x1) << 0)
+#define G_000100_ENABLE_PT(x) (((x) >> 0) & 0x1)
+#define C_000100_ENABLE_PT 0xFFFFFFFE
+#define S_000100_EFFECTIVE_L2_CACHE_SIZE(x) (((x) & 0x7) << 15)
+#define G_000100_EFFECTIVE_L2_CACHE_SIZE(x) (((x) >> 15) & 0x7)
+#define C_000100_EFFECTIVE_L2_CACHE_SIZE 0xFFFC7FFF
+#define S_000100_EFFECTIVE_L2_QUEUE_SIZE(x) (((x) & 0x7) << 21)
+#define G_000100_EFFECTIVE_L2_QUEUE_SIZE(x) (((x) >> 21) & 0x7)
+#define C_000100_EFFECTIVE_L2_QUEUE_SIZE 0xFF1FFFFF
+#define S_000100_INVALIDATE_ALL_L1_TLBS(x) (((x) & 0x1) << 28)
+#define G_000100_INVALIDATE_ALL_L1_TLBS(x) (((x) >> 28) & 0x1)
+#define C_000100_INVALIDATE_ALL_L1_TLBS 0xEFFFFFFF
+#define S_000100_INVALIDATE_L2_CACHE(x) (((x) & 0x1) << 29)
+#define G_000100_INVALIDATE_L2_CACHE(x) (((x) >> 29) & 0x1)
+#define C_000100_INVALIDATE_L2_CACHE 0xDFFFFFFF
+#define R_000102_MC_PT0_CONTEXT0_CNTL 0x000102
+#define S_000102_ENABLE_PAGE_TABLE(x) (((x) & 0x1) << 0)
+#define G_000102_ENABLE_PAGE_TABLE(x) (((x) >> 0) & 0x1)
+#define C_000102_ENABLE_PAGE_TABLE 0xFFFFFFFE
+#define S_000102_PAGE_TABLE_DEPTH(x) (((x) & 0x3) << 1)
+#define G_000102_PAGE_TABLE_DEPTH(x) (((x) >> 1) & 0x3)
+#define C_000102_PAGE_TABLE_DEPTH 0xFFFFFFF9
+#define V_000102_PAGE_TABLE_FLAT 0
+/* R600 documentation suggest that this should be a number of pages */
+#define R_000112_MC_PT0_SYSTEM_APERTURE_LOW_ADDR 0x000112
+#define R_000114_MC_PT0_SYSTEM_APERTURE_HIGH_ADDR 0x000114
+#define R_00011C_MC_PT0_CONTEXT0_DEFAULT_READ_ADDR 0x00011C
+#define R_00012C_MC_PT0_CONTEXT0_FLAT_BASE_ADDR 0x00012C
+#define R_00013C_MC_PT0_CONTEXT0_FLAT_START_ADDR 0x00013C
+#define R_00014C_MC_PT0_CONTEXT0_FLAT_END_ADDR 0x00014C
+#define R_00016C_MC_PT0_CLIENT0_CNTL 0x00016C
+#define S_00016C_ENABLE_TRANSLATION_MODE_OVERRIDE(x) (((x) & 0x1) << 0)
+#define G_00016C_ENABLE_TRANSLATION_MODE_OVERRIDE(x) (((x) >> 0) & 0x1)
+#define C_00016C_ENABLE_TRANSLATION_MODE_OVERRIDE 0xFFFFFFFE
+#define S_00016C_TRANSLATION_MODE_OVERRIDE(x) (((x) & 0x1) << 1)
+#define G_00016C_TRANSLATION_MODE_OVERRIDE(x) (((x) >> 1) & 0x1)
+#define C_00016C_TRANSLATION_MODE_OVERRIDE 0xFFFFFFFD
+#define S_00016C_SYSTEM_ACCESS_MODE_MASK(x) (((x) & 0x3) << 8)
+#define G_00016C_SYSTEM_ACCESS_MODE_MASK(x) (((x) >> 8) & 0x3)
+#define C_00016C_SYSTEM_ACCESS_MODE_MASK 0xFFFFFCFF
+#define V_00016C_SYSTEM_ACCESS_MODE_PA_ONLY 0
+#define V_00016C_SYSTEM_ACCESS_MODE_USE_SYS_MAP 1
+#define V_00016C_SYSTEM_ACCESS_MODE_IN_SYS 2
+#define V_00016C_SYSTEM_ACCESS_MODE_NOT_IN_SYS 3
+#define S_00016C_SYSTEM_APERTURE_UNMAPPED_ACCESS(x) (((x) & 0x1) << 10)
+#define G_00016C_SYSTEM_APERTURE_UNMAPPED_ACCESS(x) (((x) >> 10) & 0x1)
+#define C_00016C_SYSTEM_APERTURE_UNMAPPED_ACCESS 0xFFFFFBFF
+#define V_00016C_SYSTEM_APERTURE_UNMAPPED_PASSTHROUGH 0
+#define V_00016C_SYSTEM_APERTURE_UNMAPPED_DEFAULT_PAGE 1
+#define S_00016C_EFFECTIVE_L1_CACHE_SIZE(x) (((x) & 0x7) << 11)
+#define G_00016C_EFFECTIVE_L1_CACHE_SIZE(x) (((x) >> 11) & 0x7)
+#define C_00016C_EFFECTIVE_L1_CACHE_SIZE 0xFFFFC7FF
+#define S_00016C_ENABLE_FRAGMENT_PROCESSING(x) (((x) & 0x1) << 14)
+#define G_00016C_ENABLE_FRAGMENT_PROCESSING(x) (((x) >> 14) & 0x1)
+#define C_00016C_ENABLE_FRAGMENT_PROCESSING 0xFFFFBFFF
+#define S_00016C_EFFECTIVE_L1_QUEUE_SIZE(x) (((x) & 0x7) << 15)
+#define G_00016C_EFFECTIVE_L1_QUEUE_SIZE(x) (((x) >> 15) & 0x7)
+#define C_00016C_EFFECTIVE_L1_QUEUE_SIZE 0xFFFC7FFF
+#define S_00016C_INVALIDATE_L1_TLB(x) (((x) & 0x1) << 20)
+#define G_00016C_INVALIDATE_L1_TLB(x) (((x) >> 20) & 0x1)
+#define C_00016C_INVALIDATE_L1_TLB 0xFFEFFFFF
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 7a0098ddf977..025e3225346c 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -26,105 +26,29 @@
* Jerome Glisse
*/
#include "drmP.h"
-#include "radeon_reg.h"
#include "radeon.h"
-#include "rs690r.h"
#include "atom.h"
-#include "atom-bits.h"
-
-/* rs690,rs740 depends on : */
-void r100_hdp_reset(struct radeon_device *rdev);
-int r300_mc_wait_for_idle(struct radeon_device *rdev);
-void r420_pipes_init(struct radeon_device *rdev);
-void rs400_gart_disable(struct radeon_device *rdev);
-int rs400_gart_enable(struct radeon_device *rdev);
-void rs400_gart_adjust_size(struct radeon_device *rdev);
-void rs600_mc_disable_clients(struct radeon_device *rdev);
-
-/* This files gather functions specifics to :
- * rs690,rs740
- *
- * Some of these functions might be used by newer ASICs.
- */
-void rs690_gpu_init(struct radeon_device *rdev);
-int rs690_mc_wait_for_idle(struct radeon_device *rdev);
-
-
-/*
- * MC functions.
- */
-int rs690_mc_init(struct radeon_device *rdev)
-{
- uint32_t tmp;
- int r;
-
- if (r100_debugfs_rbbm_init(rdev)) {
- DRM_ERROR("Failed to register debugfs file for RBBM !\n");
- }
-
- rs690_gpu_init(rdev);
- rs400_gart_disable(rdev);
-
- /* Setup GPU memory space */
- rdev->mc.gtt_location = rdev->mc.mc_vram_size;
- rdev->mc.gtt_location += (rdev->mc.gtt_size - 1);
- rdev->mc.gtt_location &= ~(rdev->mc.gtt_size - 1);
- rdev->mc.vram_location = 0xFFFFFFFFUL;
- r = radeon_mc_setup(rdev);
- if (r) {
- return r;
- }
-
- /* Program GPU memory space */
- rs600_mc_disable_clients(rdev);
- if (rs690_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "Failed to wait MC idle while "
- "programming pipes. Bad things might happen.\n");
- }
- tmp = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
- tmp = REG_SET(RS690_MC_FB_TOP, tmp >> 16);
- tmp |= REG_SET(RS690_MC_FB_START, rdev->mc.vram_location >> 16);
- WREG32_MC(RS690_MCCFG_FB_LOCATION, tmp);
- /* FIXME: Does this reg exist on RS480,RS740 ? */
- WREG32(0x310, rdev->mc.vram_location);
- WREG32(RS690_HDP_FB_LOCATION, rdev->mc.vram_location >> 16);
- return 0;
-}
-
-void rs690_mc_fini(struct radeon_device *rdev)
-{
-}
-
+#include "rs690d.h"
-/*
- * Global GPU functions
- */
-int rs690_mc_wait_for_idle(struct radeon_device *rdev)
+static int rs690_mc_wait_for_idle(struct radeon_device *rdev)
{
unsigned i;
uint32_t tmp;
for (i = 0; i < rdev->usec_timeout; i++) {
/* read MC_STATUS */
- tmp = RREG32_MC(RS690_MC_STATUS);
- if (tmp & RS690_MC_STATUS_IDLE) {
+ tmp = RREG32_MC(R_000090_MC_SYSTEM_STATUS);
+ if (G_000090_MC_SYSTEM_IDLE(tmp))
return 0;
- }
- DRM_UDELAY(1);
+ udelay(1);
}
return -1;
}
-void rs690_errata(struct radeon_device *rdev)
-{
- rdev->pll_errata = 0;
-}
-
-void rs690_gpu_init(struct radeon_device *rdev)
+static void rs690_gpu_init(struct radeon_device *rdev)
{
/* FIXME: HDP same place on rs690 ? */
r100_hdp_reset(rdev);
- rv515_vga_render_disable(rdev);
/* FIXME: is this correct ? */
r420_pipes_init(rdev);
if (rs690_mc_wait_for_idle(rdev)) {
@@ -133,10 +57,6 @@ void rs690_gpu_init(struct radeon_device *rdev)
}
}
-
-/*
- * VRAM info.
- */
void rs690_pm_info(struct radeon_device *rdev)
{
int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo);
@@ -250,39 +170,39 @@ void rs690_line_buffer_adjust(struct radeon_device *rdev,
/*
* Line Buffer Setup
* There is a single line buffer shared by both display controllers.
- * DC_LB_MEMORY_SPLIT controls how that line buffer is shared between
+ * R_006520_DC_LB_MEMORY_SPLIT controls how that line buffer is shared between
* the display controllers. The paritioning can either be done
* manually or via one of four preset allocations specified in bits 1:0:
* 0 - line buffer is divided in half and shared between crtc
* 1 - D1 gets 3/4 of the line buffer, D2 gets 1/4
* 2 - D1 gets the whole buffer
* 3 - D1 gets 1/4 of the line buffer, D2 gets 3/4
- * Setting bit 2 of DC_LB_MEMORY_SPLIT controls switches to manual
+ * Setting bit 2 of R_006520_DC_LB_MEMORY_SPLIT controls switches to manual
* allocation mode. In manual allocation mode, D1 always starts at 0,
* D1 end/2 is specified in bits 14:4; D2 allocation follows D1.
*/
- tmp = RREG32(DC_LB_MEMORY_SPLIT) & ~DC_LB_MEMORY_SPLIT_MASK;
- tmp &= ~DC_LB_MEMORY_SPLIT_SHIFT_MODE;
+ tmp = RREG32(R_006520_DC_LB_MEMORY_SPLIT) & C_006520_DC_LB_MEMORY_SPLIT;
+ tmp &= ~C_006520_DC_LB_MEMORY_SPLIT_MODE;
/* auto */
if (mode1 && mode2) {
if (mode1->hdisplay > mode2->hdisplay) {
if (mode1->hdisplay > 2560)
- tmp |= DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q;
+ tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q;
else
- tmp |= DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
+ tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
} else if (mode2->hdisplay > mode1->hdisplay) {
if (mode2->hdisplay > 2560)
- tmp |= DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
+ tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
else
- tmp |= DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
+ tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
} else
- tmp |= AVIVO_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
+ tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF;
} else if (mode1) {
- tmp |= DC_LB_MEMORY_SPLIT_D1_ONLY;
+ tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_ONLY;
} else if (mode2) {
- tmp |= DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
+ tmp |= V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q;
}
- WREG32(DC_LB_MEMORY_SPLIT, tmp);
+ WREG32(R_006520_DC_LB_MEMORY_SPLIT, tmp);
}
struct rs690_watermark {
@@ -487,28 +407,28 @@ void rs690_bandwidth_update(struct radeon_device *rdev)
* option.
*/
if (rdev->disp_priority == 2) {
- tmp = RREG32_MC(MC_INIT_MISC_LAT_TIMER);
- tmp &= ~MC_DISP1R_INIT_LAT_MASK;
- tmp &= ~MC_DISP0R_INIT_LAT_MASK;
- if (mode1)
- tmp |= (1 << MC_DISP1R_INIT_LAT_SHIFT);
+ tmp = RREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER);
+ tmp &= C_000104_MC_DISP0R_INIT_LAT;
+ tmp &= C_000104_MC_DISP1R_INIT_LAT;
if (mode0)
- tmp |= (1 << MC_DISP0R_INIT_LAT_SHIFT);
- WREG32_MC(MC_INIT_MISC_LAT_TIMER, tmp);
+ tmp |= S_000104_MC_DISP0R_INIT_LAT(1);
+ if (mode1)
+ tmp |= S_000104_MC_DISP1R_INIT_LAT(1);
+ WREG32_MC(R_000104_MC_INIT_MISC_LAT_TIMER, tmp);
}
rs690_line_buffer_adjust(rdev, mode0, mode1);
if ((rdev->family == CHIP_RS690) || (rdev->family == CHIP_RS740))
- WREG32(DCP_CONTROL, 0);
+ WREG32(R_006C9C_DCP_CONTROL, 0);
if ((rdev->family == CHIP_RS780) || (rdev->family == CHIP_RS880))
- WREG32(DCP_CONTROL, 2);
+ WREG32(R_006C9C_DCP_CONTROL, 2);
rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[0], &wm0);
rs690_crtc_bandwidth_compute(rdev, rdev->mode_info.crtcs[1], &wm1);
tmp = (wm0.lb_request_fifo_depth - 1);
tmp |= (wm1.lb_request_fifo_depth - 1) << 16;
- WREG32(LB_MAX_REQ_OUTSTANDING, tmp);
+ WREG32(R_006D58_LB_MAX_REQ_OUTSTANDING, tmp);
if (mode0 && mode1) {
if (rfixed_trunc(wm0.dbpp) > 64)
@@ -561,10 +481,10 @@ void rs690_bandwidth_update(struct radeon_device *rdev)
priority_mark12.full = 0;
if (wm1.priority_mark_max.full > priority_mark12.full)
priority_mark12.full = wm1.priority_mark_max.full;
- WREG32(D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02));
- WREG32(D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02));
- WREG32(D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12));
- WREG32(D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12));
+ WREG32(R_006548_D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02));
+ WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02));
+ WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12));
+ WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12));
} else if (mode0) {
if (rfixed_trunc(wm0.dbpp) > 64)
a.full = rfixed_mul(wm0.dbpp, wm0.num_line_pair);
@@ -591,10 +511,12 @@ void rs690_bandwidth_update(struct radeon_device *rdev)
priority_mark02.full = 0;
if (wm0.priority_mark_max.full > priority_mark02.full)
priority_mark02.full = wm0.priority_mark_max.full;
- WREG32(D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02));
- WREG32(D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02));
- WREG32(D2MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF);
- WREG32(D2MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF);
+ WREG32(R_006548_D1MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark02));
+ WREG32(R_00654C_D1MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark02));
+ WREG32(R_006D48_D2MODE_PRIORITY_A_CNT,
+ S_006D48_D2MODE_PRIORITY_A_OFF(1));
+ WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT,
+ S_006D4C_D2MODE_PRIORITY_B_OFF(1));
} else {
if (rfixed_trunc(wm1.dbpp) > 64)
a.full = rfixed_mul(wm1.dbpp, wm1.num_line_pair);
@@ -621,30 +543,203 @@ void rs690_bandwidth_update(struct radeon_device *rdev)
priority_mark12.full = 0;
if (wm1.priority_mark_max.full > priority_mark12.full)
priority_mark12.full = wm1.priority_mark_max.full;
- WREG32(D1MODE_PRIORITY_A_CNT, MODE_PRIORITY_OFF);
- WREG32(D1MODE_PRIORITY_B_CNT, MODE_PRIORITY_OFF);
- WREG32(D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12));
- WREG32(D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12));
+ WREG32(R_006548_D1MODE_PRIORITY_A_CNT,
+ S_006548_D1MODE_PRIORITY_A_OFF(1));
+ WREG32(R_00654C_D1MODE_PRIORITY_B_CNT,
+ S_00654C_D1MODE_PRIORITY_B_OFF(1));
+ WREG32(R_006D48_D2MODE_PRIORITY_A_CNT, rfixed_trunc(priority_mark12));
+ WREG32(R_006D4C_D2MODE_PRIORITY_B_CNT, rfixed_trunc(priority_mark12));
}
}
-/*
- * Indirect registers accessor
- */
uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg)
{
uint32_t r;
- WREG32(RS690_MC_INDEX, (reg & RS690_MC_INDEX_MASK));
- r = RREG32(RS690_MC_DATA);
- WREG32(RS690_MC_INDEX, RS690_MC_INDEX_MASK);
+ WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg));
+ r = RREG32(R_00007C_MC_DATA);
+ WREG32(R_000078_MC_INDEX, ~C_000078_MC_IND_ADDR);
return r;
}
void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v)
{
- WREG32(RS690_MC_INDEX,
- RS690_MC_INDEX_WR_EN | ((reg) & RS690_MC_INDEX_MASK));
- WREG32(RS690_MC_DATA, v);
- WREG32(RS690_MC_INDEX, RS690_MC_INDEX_WR_ACK);
+ WREG32(R_000078_MC_INDEX, S_000078_MC_IND_ADDR(reg) |
+ S_000078_MC_IND_WR_EN(1));
+ WREG32(R_00007C_MC_DATA, v);
+ WREG32(R_000078_MC_INDEX, 0x7F);
+}
+
+void rs690_mc_program(struct radeon_device *rdev)
+{
+ struct rv515_mc_save save;
+
+ /* Stops all mc clients */
+ rv515_mc_stop(rdev, &save);
+
+ /* Wait for mc idle */
+ if (rs690_mc_wait_for_idle(rdev))
+ dev_warn(rdev->dev, "Wait MC idle timeout before updating MC.\n");
+ /* Program MC, should be a 32bits limited address space */
+ WREG32_MC(R_000100_MCCFG_FB_LOCATION,
+ S_000100_MC_FB_START(rdev->mc.vram_start >> 16) |
+ S_000100_MC_FB_TOP(rdev->mc.vram_end >> 16));
+ WREG32(R_000134_HDP_FB_LOCATION,
+ S_000134_HDP_FB_START(rdev->mc.vram_start >> 16));
+
+ rv515_mc_resume(rdev, &save);
+}
+
+static int rs690_startup(struct radeon_device *rdev)
+{
+ int r;
+
+ rs690_mc_program(rdev);
+ /* Resume clock */
+ rv515_clock_startup(rdev);
+ /* Initialize GPU configuration (# pipes, ...) */
+ rs690_gpu_init(rdev);
+ /* Initialize GART (initialize after TTM so we can allocate
+ * memory through TTM but finalize after TTM) */
+ r = rs400_gart_enable(rdev);
+ if (r)
+ return r;
+ /* Enable IRQ */
+ rdev->irq.sw_int = true;
+ rs600_irq_set(rdev);
+ /* 1M ring buffer */
+ r = r100_cp_init(rdev, 1024 * 1024);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing CP (%d).\n", r);
+ return r;
+ }
+ r = r100_wb_init(rdev);
+ if (r)
+ dev_err(rdev->dev, "failled initializing WB (%d).\n", r);
+ r = r100_ib_init(rdev);
+ if (r) {
+ dev_err(rdev->dev, "failled initializing IB (%d).\n", r);
+ return r;
+ }
+ return 0;
+}
+
+int rs690_resume(struct radeon_device *rdev)
+{
+ /* Make sur GART are not working */
+ rs400_gart_disable(rdev);
+ /* Resume clock before doing reset */
+ rv515_clock_startup(rdev);
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_reset(rdev)) {
+ dev_warn(rdev->dev, "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
+ RREG32(R_000E40_RBBM_STATUS),
+ RREG32(R_0007C0_CP_STAT));
+ }
+ /* post */
+ atom_asic_init(rdev->mode_info.atom_context);
+ /* Resume clock after posting */
+ rv515_clock_startup(rdev);
+ return rs690_startup(rdev);
+}
+
+int rs690_suspend(struct radeon_device *rdev)
+{
+ r100_cp_disable(rdev);
+ r100_wb_disable(rdev);
+ rs600_irq_disable(rdev);
+ rs400_gart_disable(rdev);
+ return 0;
+}
+
+void rs690_fini(struct radeon_device *rdev)
+{
+ rs690_suspend(rdev);
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ radeon_gem_fini(rdev);
+ rs400_gart_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ radeon_fence_driver_fini(rdev);
+ radeon_object_fini(rdev);
+ radeon_atombios_fini(rdev);
+ kfree(rdev->bios);
+ rdev->bios = NULL;
+}
+
+int rs690_init(struct radeon_device *rdev)
+{
+ int r;
+
+ /* Disable VGA */
+ rv515_vga_render_disable(rdev);
+ /* Initialize scratch registers */
+ radeon_scratch_init(rdev);
+ /* Initialize surface registers */
+ radeon_surface_init(rdev);
+ /* TODO: disable VGA need to use VGA request */
+ /* BIOS*/
+ if (!radeon_get_bios(rdev)) {
+ if (ASIC_IS_AVIVO(rdev))
+ return -EINVAL;
+ }
+ if (rdev->is_atom_bios) {
+ r = radeon_atombios_init(rdev);
+ if (r)
+ return r;
+ } else {
+ dev_err(rdev->dev, "Expecting atombios for RV515 GPU\n");
+ return -EINVAL;
+ }
+ /* Reset gpu before posting otherwise ATOM will enter infinite loop */
+ if (radeon_gpu_reset(rdev)) {
+ dev_warn(rdev->dev,
+ "GPU reset failed ! (0xE40=0x%08X, 0x7C0=0x%08X)\n",
+ RREG32(R_000E40_RBBM_STATUS),
+ RREG32(R_0007C0_CP_STAT));
+ }
+ /* check if cards are posted or not */
+ if (!radeon_card_posted(rdev) && rdev->bios) {
+ DRM_INFO("GPU not posted. posting now...\n");
+ atom_asic_init(rdev->mode_info.atom_context);
+ }
+ /* Initialize clocks */
+ radeon_get_clock_info(rdev->ddev);
+ /* Get vram informations */
+ rs690_vram_info(rdev);
+ /* Initialize memory controller (also test AGP) */
+ r = r420_mc_init(rdev);
+ if (r)
+ return r;
+ rv515_debugfs(rdev);
+ /* Fence driver */
+ r = radeon_fence_driver_init(rdev);
+ if (r)
+ return r;
+ r = radeon_irq_kms_init(rdev);
+ if (r)
+ return r;
+ /* Memory manager */
+ r = radeon_object_init(rdev);
+ if (r)
+ return r;
+ r = rs400_gart_init(rdev);
+ if (r)
+ return r;
+ rs600_set_safe_registers(rdev);
+ rdev->accel_working = true;
+ r = rs690_startup(rdev);
+ if (r) {
+ /* Somethings want wront with the accel init stop accel */
+ dev_err(rdev->dev, "Disabling GPU acceleration\n");
+ rs690_suspend(rdev);
+ r100_cp_fini(rdev);
+ r100_wb_fini(rdev);
+ r100_ib_fini(rdev);
+ rs400_gart_fini(rdev);
+ radeon_irq_kms_fini(rdev);
+ rdev->accel_working = false;
+ }
+ return 0;
}
diff --git a/drivers/gpu/drm/radeon/rs690d.h b/drivers/gpu/drm/radeon/rs690d.h
new file mode 100644
index 000000000000..62d31e7a897f
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rs690d.h
@@ -0,0 +1,307 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#ifndef __RS690D_H__
+#define __RS690D_H__
+
+/* Registers */
+#define R_000078_MC_INDEX 0x000078
+#define S_000078_MC_IND_ADDR(x) (((x) & 0x1FF) << 0)
+#define G_000078_MC_IND_ADDR(x) (((x) >> 0) & 0x1FF)
+#define C_000078_MC_IND_ADDR 0xFFFFFE00
+#define S_000078_MC_IND_WR_EN(x) (((x) & 0x1) << 9)
+#define G_000078_MC_IND_WR_EN(x) (((x) >> 9) & 0x1)
+#define C_000078_MC_IND_WR_EN 0xFFFFFDFF
+#define R_00007C_MC_DATA 0x00007C
+#define S_00007C_MC_DATA(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_00007C_MC_DATA(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_00007C_MC_DATA 0x00000000
+#define R_0000F8_CONFIG_MEMSIZE 0x0000F8
+#define S_0000F8_CONFIG_MEMSIZE(x) (((x) & 0xFFFFFFFF) << 0)
+#define G_0000F8_CONFIG_MEMSIZE(x) (((x) >> 0) & 0xFFFFFFFF)
+#define C_0000F8_CONFIG_MEMSIZE 0x00000000
+#define R_000134_HDP_FB_LOCATION 0x000134
+#define S_000134_HDP_FB_START(x) (((x) & 0xFFFF) << 0)
+#define G_000134_HDP_FB_START(x) (((x) >> 0) & 0xFFFF)
+#define C_000134_HDP_FB_START 0xFFFF0000
+#define R_0007C0_CP_STAT 0x0007C0
+#define S_0007C0_MRU_BUSY(x) (((x) & 0x1) << 0)
+#define G_0007C0_MRU_BUSY(x) (((x) >> 0) & 0x1)
+#define C_0007C0_MRU_BUSY 0xFFFFFFFE
+#define S_0007C0_MWU_BUSY(x) (((x) & 0x1) << 1)
+#define G_0007C0_MWU_BUSY(x) (((x) >> 1) & 0x1)
+#define C_0007C0_MWU_BUSY 0xFFFFFFFD
+#define S_0007C0_RSIU_BUSY(x) (((x) & 0x1) << 2)
+#define G_0007C0_RSIU_BUSY(x) (((x) >> 2) & 0x1)
+#define C_0007C0_RSIU_BUSY 0xFFFFFFFB
+#define S_0007C0_RCIU_BUSY(x) (((x) & 0x1) << 3)
+#define G_0007C0_RCIU_BUSY(x) (((x) >> 3) & 0x1)
+#define C_0007C0_RCIU_BUSY 0xFFFFFFF7
+#define S_0007C0_CSF_PRIMARY_BUSY(x) (((x) & 0x1) << 9)
+#define G_0007C0_CSF_PRIMARY_BUSY(x) (((x) >> 9) & 0x1)
+#define C_0007C0_CSF_PRIMARY_BUSY 0xFFFFFDFF
+#define S_0007C0_CSF_INDIRECT_BUSY(x) (((x) & 0x1) << 10)
+#define G_0007C0_CSF_INDIRECT_BUSY(x) (((x) >> 10) & 0x1)
+#define C_0007C0_CSF_INDIRECT_BUSY 0xFFFFFBFF
+#define S_0007C0_CSQ_PRIMARY_BUSY(x) (((x) & 0x1) << 11)
+#define G_0007C0_CSQ_PRIMARY_BUSY(x) (((x) >> 11) & 0x1)
+#define C_0007C0_CSQ_PRIMARY_BUSY 0xFFFFF7FF
+#define S_0007C0_CSQ_INDIRECT_BUSY(x) (((x) & 0x1) << 12)
+#define G_0007C0_CSQ_INDIRECT_BUSY(x) (((x) >> 12) & 0x1)
+#define C_0007C0_CSQ_INDIRECT_BUSY 0xFFFFEFFF
+#define S_0007C0_CSI_BUSY(x) (((x) & 0x1) << 13)
+#define G_0007C0_CSI_BUSY(x) (((x) >> 13) & 0x1)
+#define C_0007C0_CSI_BUSY 0xFFFFDFFF
+#define S_0007C0_CSF_INDIRECT2_BUSY(x) (((x) & 0x1) << 14)
+#define G_0007C0_CSF_INDIRECT2_BUSY(x) (((x) >> 14) & 0x1)
+#define C_0007C0_CSF_INDIRECT2_BUSY 0xFFFFBFFF
+#define S_0007C0_CSQ_INDIRECT2_BUSY(x) (((x) & 0x1) << 15)
+#define G_0007C0_CSQ_INDIRECT2_BUSY(x) (((x) >> 15) & 0x1)
+#define C_0007C0_CSQ_INDIRECT2_BUSY 0xFFFF7FFF
+#define S_0007C0_GUIDMA_BUSY(x) (((x) & 0x1) << 28)
+#define G_0007C0_GUIDMA_BUSY(x) (((x) >> 28) & 0x1)
+#define C_0007C0_GUIDMA_BUSY 0xEFFFFFFF
+#define S_0007C0_VIDDMA_BUSY(x) (((x) & 0x1) << 29)
+#define G_0007C0_VIDDMA_BUSY(x) (((x) >> 29) & 0x1)
+#define C_0007C0_VIDDMA_BUSY 0xDFFFFFFF
+#define S_0007C0_CMDSTRM_BUSY(x) (((x) & 0x1) << 30)
+#define G_0007C0_CMDSTRM_BUSY(x) (((x) >> 30) & 0x1)
+#define C_0007C0_CMDSTRM_BUSY 0xBFFFFFFF
+#define S_0007C0_CP_BUSY(x) (((x) & 0x1) << 31)
+#define G_0007C0_CP_BUSY(x) (((x) >> 31) & 0x1)
+#define C_0007C0_CP_BUSY 0x7FFFFFFF
+#define R_000E40_RBBM_STATUS 0x000E40
+#define S_000E40_CMDFIFO_AVAIL(x) (((x) & 0x7F) << 0)
+#define G_000E40_CMDFIFO_AVAIL(x) (((x) >> 0) & 0x7F)
+#define C_000E40_CMDFIFO_AVAIL 0xFFFFFF80
+#define S_000E40_HIRQ_ON_RBB(x) (((x) & 0x1) << 8)
+#define G_000E40_HIRQ_ON_RBB(x) (((x) >> 8) & 0x1)
+#define C_000E40_HIRQ_ON_RBB 0xFFFFFEFF
+#define S_000E40_CPRQ_ON_RBB(x) (((x) & 0x1) << 9)
+#define G_000E40_CPRQ_ON_RBB(x) (((x) >> 9) & 0x1)
+#define C_000E40_CPRQ_ON_RBB 0xFFFFFDFF
+#define S_000E40_CFRQ_ON_RBB(x) (((x) & 0x1) << 10)
+#define G_000E40_CFRQ_ON_RBB(x) (((x) >> 10) & 0x1)
+#define C_000E40_CFRQ_ON_RBB 0xFFFFFBFF
+#define S_000E40_HIRQ_IN_RTBUF(x) (((x) & 0x1) << 11)
+#define G_000E40_HIRQ_IN_RTBUF(x) (((x) >> 11) & 0x1)
+#define C_000E40_HIRQ_IN_RTBUF 0xFFFFF7FF
+#define S_000E40_CPRQ_IN_RTBUF(x) (((x) & 0x1) << 12)
+#define G_000E40_CPRQ_IN_RTBUF(x) (((x) >> 12) & 0x1)
+#define C_000E40_CPRQ_IN_RTBUF 0xFFFFEFFF
+#define S_000E40_CFRQ_IN_RTBUF(x) (((x) & 0x1) << 13)
+#define G_000E40_CFRQ_IN_RTBUF(x) (((x) >> 13) & 0x1)
+#define C_000E40_CFRQ_IN_RTBUF 0xFFFFDFFF
+#define S_000E40_CF_PIPE_BUSY(x) (((x) & 0x1) << 14)
+#define G_000E40_CF_PIPE_BUSY(x) (((x) >> 14) & 0x1)
+#define C_000E40_CF_PIPE_BUSY 0xFFFFBFFF
+#define S_000E40_ENG_EV_BUSY(x) (((x) & 0x1) << 15)
+#define G_000E40_ENG_EV_BUSY(x) (((x) >> 15) & 0x1)
+#define C_000E40_ENG_EV_BUSY 0xFFFF7FFF
+#define S_000E40_CP_CMDSTRM_BUSY(x) (((x) & 0x1) << 16)
+#define G_000E40_CP_CMDSTRM_BUSY(x) (((x) >> 16) & 0x1)
+#define C_000E40_CP_CMDSTRM_BUSY 0xFFFEFFFF
+#define S_000E40_E2_BUSY(x) (((x) & 0x1) << 17)
+#define G_000E40_E2_BUSY(x) (((x) >> 17) & 0x1)
+#define C_000E40_E2_BUSY 0xFFFDFFFF
+#define S_000E40_RB2D_BUSY(x) (((x) & 0x1) << 18)
+#define G_000E40_RB2D_BUSY(x) (((x) >> 18) & 0x1)
+#define C_000E40_RB2D_BUSY 0xFFFBFFFF
+#define S_000E40_RB3D_BUSY(x) (((x) & 0x1) << 19)
+#define G_000E40_RB3D_BUSY(x) (((x) >> 19) & 0x1)
+#define C_000E40_RB3D_BUSY 0xFFF7FFFF
+#define S_000E40_VAP_BUSY(x) (((x) & 0x1) << 20)
+#define G_000E40_VAP_BUSY(x) (((x) >> 20) & 0x1)
+#define C_000E40_VAP_BUSY 0xFFEFFFFF
+#define S_000E40_RE_BUSY(x) (((x) & 0x1) << 21)
+#define G_000E40_RE_BUSY(x) (((x) >> 21) & 0x1)
+#define C_000E40_RE_BUSY 0xFFDFFFFF
+#define S_000E40_TAM_BUSY(x) (((x) & 0x1) << 22)
+#define G_000E40_TAM_BUSY(x) (((x) >> 22) & 0x1)
+#define C_000E40_TAM_BUSY 0xFFBFFFFF
+#define S_000E40_TDM_BUSY(x) (((x) & 0x1) << 23)
+#define G_000E40_TDM_BUSY(x) (((x) >> 23) & 0x1)
+#define C_000E40_TDM_BUSY 0xFF7FFFFF
+#define S_000E40_PB_BUSY(x) (((x) & 0x1) << 24)
+#define G_000E40_PB_BUSY(x) (((x) >> 24) & 0x1)
+#define C_000E40_PB_BUSY 0xFEFFFFFF
+#define S_000E40_TIM_BUSY(x) (((x) & 0x1) << 25)
+#define G_000E40_TIM_BUSY(x) (((x) >> 25) & 0x1)
+#define C_000E40_TIM_BUSY 0xFDFFFFFF
+#define S_000E40_GA_BUSY(x) (((x) & 0x1) << 26)
+#define G_000E40_GA_BUSY(x) (((x) >> 26) & 0x1)
+#define C_000E40_GA_BUSY 0xFBFFFFFF
+#define S_000E40_CBA2D_BUSY(x) (((x) & 0x1) << 27)
+#define G_000E40_CBA2D_BUSY(x) (((x) >> 27) & 0x1)
+#define C_000E40_CBA2D_BUSY 0xF7FFFFFF
+#define S_000E40_GUI_ACTIVE(x) (((x) & 0x1) << 31)
+#define G_000E40_GUI_ACTIVE(x) (((x) >> 31) & 0x1)
+#define C_000E40_GUI_ACTIVE 0x7FFFFFFF
+#define R_006520_DC_LB_MEMORY_SPLIT 0x006520
+#define S_006520_DC_LB_MEMORY_SPLIT(x) (((x) & 0x3) << 0)
+#define G_006520_DC_LB_MEMORY_SPLIT(x) (((x) >> 0) & 0x3)
+#define C_006520_DC_LB_MEMORY_SPLIT 0xFFFFFFFC
+#define S_006520_DC_LB_MEMORY_SPLIT_MODE(x) (((x) & 0x1) << 2)
+#define G_006520_DC_LB_MEMORY_SPLIT_MODE(x) (((x) >> 2) & 0x1)
+#define C_006520_DC_LB_MEMORY_SPLIT_MODE 0xFFFFFFFB
+#define V_006520_DC_LB_MEMORY_SPLIT_D1HALF_D2HALF 0
+#define V_006520_DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q 1
+#define V_006520_DC_LB_MEMORY_SPLIT_D1_ONLY 2
+#define V_006520_DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q 3
+#define S_006520_DC_LB_DISP1_END_ADR(x) (((x) & 0x7FF) << 4)
+#define G_006520_DC_LB_DISP1_END_ADR(x) (((x) >> 4) & 0x7FF)
+#define C_006520_DC_LB_DISP1_END_ADR 0xFFFF800F
+#define R_006548_D1MODE_PRIORITY_A_CNT 0x006548
+#define S_006548_D1MODE_PRIORITY_MARK_A(x) (((x) & 0x7FFF) << 0)
+#define G_006548_D1MODE_PRIORITY_MARK_A(x) (((x) >> 0) & 0x7FFF)
+#define C_006548_D1MODE_PRIORITY_MARK_A 0xFFFF8000
+#define S_006548_D1MODE_PRIORITY_A_OFF(x) (((x) & 0x1) << 16)
+#define G_006548_D1MODE_PRIORITY_A_OFF(x) (((x) >> 16) & 0x1)
+#define C_006548_D1MODE_PRIORITY_A_OFF 0xFFFEFFFF
+#define S_006548_D1MODE_PRIORITY_A_FORCE_MASK(x) (((x) & 0x1) << 24)
+#define G_006548_D1MODE_PRIORITY_A_FORCE_MASK(x) (((x) >> 24) & 0x1)
+#define C_006548_D1MODE_PRIORITY_A_FORCE_MASK 0xFEFFFFFF
+#define R_00654C_D1MODE_PRIORITY_B_CNT 0x00654C
+#define S_00654C_D1MODE_PRIORITY_MARK_B(x) (((x) & 0x7FFF) << 0)
+#define G_00654C_D1MODE_PRIORITY_MARK_B(x) (((x) >> 0) & 0x7FFF)
+#define C_00654C_D1MODE_PRIORITY_MARK_B 0xFFFF8000
+#define S_00654C_D1MODE_PRIORITY_B_OFF(x) (((x) & 0x1) << 16)
+#define G_00654C_D1MODE_PRIORITY_B_OFF(x) (((x) >> 16) & 0x1)
+#define C_00654C_D1MODE_PRIORITY_B_OFF 0xFFFEFFFF
+#define S_00654C_D1MODE_PRIORITY_B_ALWAYS_ON(x) (((x) & 0x1) << 20)
+#define G_00654C_D1MODE_PRIORITY_B_ALWAYS_ON(x) (((x) >> 20) & 0x1)
+#define C_00654C_D1MODE_PRIORITY_B_ALWAYS_ON 0xFFEFFFFF
+#define S_00654C_D1MODE_PRIORITY_B_FORCE_MASK(x) (((x) & 0x1) << 24)
+#define G_00654C_D1MODE_PRIORITY_B_FORCE_MASK(x) (((x) >> 24) & 0x1)
+#define C_00654C_D1MODE_PRIORITY_B_FORCE_MASK 0xFEFFFFFF
+#define R_006C9C_DCP_CONTROL 0x006C9C
+#define R_006D48_D2MODE_PRIORITY_A_CNT 0x006D48
+#define S_006D48_D2MODE_PRIORITY_MARK_A(x) (((x) & 0x7FFF) << 0)
+#define G_006D48_D2MODE_PRIORITY_MARK_A(x) (((x) >> 0) & 0x7FFF)
+#define C_006D48_D2MODE_PRIORITY_MARK_A 0xFFFF8000
+#define S_006D48_D2MODE_PRIORITY_A_OFF(x) (((x) & 0x1) << 16)
+#define G_006D48_D2MODE_PRIORITY_A_OFF(x) (((x) >> 16) & 0x1)
+#define C_006D48_D2MODE_PRIORITY_A_OFF 0xFFFEFFFF
+#define S_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(x) (((x) & 0x1) << 20)
+#define G_006D48_D2MODE_PRIORITY_A_ALWAYS_ON(x) (((x) >> 20) & 0x1)
+#define C_006D48_D2MODE_PRIORITY_A_ALWAYS_ON 0xFFEFFFFF
+#define S_006D48_D2MODE_PRIORITY_A_FORCE_MASK(x) (((x) & 0x1) << 24)
+#define G_006D48_D2MODE_PRIORITY_A_FORCE_MASK(x) (((x) >> 24) & 0x1)
+#define C_006D48_D2MODE_PRIORITY_A_FORCE_MASK 0xFEFFFFFF
+#define R_006D4C_D2MODE_PRIORITY_B_CNT 0x006D4C
+#define S_006D4C_D2MODE_PRIORITY_MARK_B(x) (((x) & 0x7FFF) << 0)
+#define G_006D4C_D2MODE_PRIORITY_MARK_B(x) (((x) >> 0) & 0x7FFF)
+#define C_006D4C_D2MODE_PRIORITY_MARK_B 0xFFFF8000
+#define S_006D4C_D2MODE_PRIORITY_B_OFF(x) (((x) & 0x1) << 16)
+#define G_006D4C_D2MODE_PRIORITY_B_OFF(x) (((x) >> 16) & 0x1)
+#define C_006D4C_D2MODE_PRIORITY_B_OFF 0xFFFEFFFF
+#define S_006D4C_D2MODE_PRIORITY_B_ALWAYS_ON(x) (((x) & 0x1) << 20)
+#define G_006D4C_D2MODE_PRIORITY_B_ALWAYS_ON(x) (((x) >> 20) & 0x1)
+#define C_006D4C_D2MODE_PRIORITY_B_ALWAYS_ON 0xFFEFFFFF
+#define S_006D4C_D2MODE_PRIORITY_B_FORCE_MASK(x) (((x) & 0x1) << 24)
+#define G_006D4C_D2MODE_PRIORITY_B_FORCE_MASK(x) (((x) >> 24) & 0x1)
+#define C_006D4C_D2MODE_PRIORITY_B_FORCE_MASK 0xFEFFFFFF
+#define R_006D58_LB_MAX_REQ_OUTSTANDING 0x006D58
+#define S_006D58_LB_D1_MAX_REQ_OUTSTANDING(x) (((x) & 0xF) << 0)
+#define G_006D58_LB_D1_MAX_REQ_OUTSTANDING(x) (((x) >> 0) & 0xF)
+#define C_006D58_LB_D1_MAX_REQ_OUTSTANDING 0xFFFFFFF0
+#define S_006D58_LB_D2_MAX_REQ_OUTSTANDING(x) (((x) & 0xF) << 16)
+#define G_006D58_LB_D2_MAX_REQ_OUTSTANDING(x) (((x) >> 16) & 0xF)
+#define C_006D58_LB_D2_MAX_REQ_OUTSTANDING 0xFFF0FFFF
+
+
+#define R_000090_MC_SYSTEM_STATUS 0x000090
+#define S_000090_MC_SYSTEM_IDLE(x) (((x) & 0x1) << 0)
+#define G_000090_MC_SYSTEM_IDLE(x) (((x) >> 0) & 0x1)
+#define C_000090_MC_SYSTEM_IDLE 0xFFFFFFFE
+#define S_000090_MC_SEQUENCER_IDLE(x) (((x) & 0x1) << 1)
+#define G_000090_MC_SEQUENCER_IDLE(x) (((x) >> 1) & 0x1)
+#define C_000090_MC_SEQUENCER_IDLE 0xFFFFFFFD
+#define S_000090_MC_ARBITER_IDLE(x) (((x) & 0x1) << 2)
+#define G_000090_MC_ARBITER_IDLE(x) (((x) >> 2) & 0x1)
+#define C_000090_MC_ARBITER_IDLE 0xFFFFFFFB
+#define S_000090_MC_SELECT_PM(x) (((x) & 0x1) << 3)
+#define G_000090_MC_SELECT_PM(x) (((x) >> 3) & 0x1)
+#define C_000090_MC_SELECT_PM 0xFFFFFFF7
+#define S_000090_RESERVED4(x) (((x) & 0xF) << 4)
+#define G_000090_RESERVED4(x) (((x) >> 4) & 0xF)
+#define C_000090_RESERVED4 0xFFFFFF0F
+#define S_000090_RESERVED8(x) (((x) & 0xF) << 8)
+#define G_000090_RESERVED8(x) (((x) >> 8) & 0xF)
+#define C_000090_RESERVED8 0xFFFFF0FF
+#define S_000090_RESERVED12(x) (((x) & 0xF) << 12)
+#define G_000090_RESERVED12(x) (((x) >> 12) & 0xF)
+#define C_000090_RESERVED12 0xFFFF0FFF
+#define S_000090_MCA_INIT_EXECUTED(x) (((x) & 0x1) << 16)
+#define G_000090_MCA_INIT_EXECUTED(x) (((x) >> 16) & 0x1)
+#define C_000090_MCA_INIT_EXECUTED 0xFFFEFFFF
+#define S_000090_MCA_IDLE(x) (((x) & 0x1) << 17)
+#define G_000090_MCA_IDLE(x) (((x) >> 17) & 0x1)
+#define C_000090_MCA_IDLE 0xFFFDFFFF
+#define S_000090_MCA_SEQ_IDLE(x) (((x) & 0x1) << 18)
+#define G_000090_MCA_SEQ_IDLE(x) (((x) >> 18) & 0x1)
+#define C_000090_MCA_SEQ_IDLE 0xFFFBFFFF
+#define S_000090_MCA_ARB_IDLE(x) (((x) & 0x1) << 19)
+#define G_000090_MCA_ARB_IDLE(x) (((x) >> 19) & 0x1)
+#define C_000090_MCA_ARB_IDLE 0xFFF7FFFF
+#define S_000090_RESERVED20(x) (((x) & 0xFFF) << 20)
+#define G_000090_RESERVED20(x) (((x) >> 20) & 0xFFF)
+#define C_000090_RESERVED20 0x000FFFFF
+#define R_000100_MCCFG_FB_LOCATION 0x000100
+#define S_000100_MC_FB_START(x) (((x) & 0xFFFF) << 0)
+#define G_000100_MC_FB_START(x) (((x) >> 0) & 0xFFFF)
+#define C_000100_MC_FB_START 0xFFFF0000
+#define S_000100_MC_FB_TOP(x) (((x) & 0xFFFF) << 16)
+#define G_000100_MC_FB_TOP(x) (((x) >> 16) & 0xFFFF)
+#define C_000100_MC_FB_TOP 0x0000FFFF
+#define R_000104_MC_INIT_MISC_LAT_TIMER 0x000104
+#define S_000104_MC_CPR_INIT_LAT(x) (((x) & 0xF) << 0)
+#define G_000104_MC_CPR_INIT_LAT(x) (((x) >> 0) & 0xF)
+#define C_000104_MC_CPR_INIT_LAT 0xFFFFFFF0
+#define S_000104_MC_VF_INIT_LAT(x) (((x) & 0xF) << 4)
+#define G_000104_MC_VF_INIT_LAT(x) (((x) >> 4) & 0xF)
+#define C_000104_MC_VF_INIT_LAT 0xFFFFFF0F
+#define S_000104_MC_DISP0R_INIT_LAT(x) (((x) & 0xF) << 8)
+#define G_000104_MC_DISP0R_INIT_LAT(x) (((x) >> 8) & 0xF)
+#define C_000104_MC_DISP0R_INIT_LAT 0xFFFFF0FF
+#define S_000104_MC_DISP1R_INIT_LAT(x) (((x) & 0xF) << 12)
+#define G_000104_MC_DISP1R_INIT_LAT(x) (((x) >> 12) & 0xF)
+#define C_000104_MC_DISP1R_INIT_LAT 0xFFFF0FFF
+#define S_000104_MC_FIXED_INIT_LAT(x) (((x) & 0xF) << 16)
+#define G_000104_MC_FIXED_INIT_LAT(x) (((x) >> 16) & 0xF)
+#define C_000104_MC_FIXED_INIT_LAT 0xFFF0FFFF
+#define S_000104_MC_E2R_INIT_LAT(x) (((x) & 0xF) << 20)
+#define G_000104_MC_E2R_INIT_LAT(x) (((x) >> 20) & 0xF)
+#define C_000104_MC_E2R_INIT_LAT 0xFF0FFFFF
+#define S_000104_SAME_PAGE_PRIO(x) (((x) & 0xF) << 24)
+#define G_000104_SAME_PAGE_PRIO(x) (((x) >> 24) & 0xF)
+#define C_000104_SAME_PAGE_PRIO 0xF0FFFFFF
+#define S_000104_MC_GLOBW_INIT_LAT(x) (((x) & 0xF) << 28)
+#define G_000104_MC_GLOBW_INIT_LAT(x) (((x) >> 28) & 0xF)
+#define C_000104_MC_GLOBW_INIT_LAT 0x0FFFFFFF
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rs690r.h b/drivers/gpu/drm/radeon/rs690r.h
deleted file mode 100644
index c0d9faa2175b..000000000000
--- a/drivers/gpu/drm/radeon/rs690r.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2008 Advanced Micro Devices, Inc.
- * Copyright 2008 Red Hat Inc.
- * Copyright 2009 Jerome Glisse.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Dave Airlie
- * Alex Deucher
- * Jerome Glisse
- */
-#ifndef RS690R_H
-#define RS690R_H
-
-/* RS690/RS740 registers */
-#define MC_INDEX 0x0078
-# define MC_INDEX_MASK 0x1FF
-# define MC_INDEX_WR_EN (1 << 9)
-# define MC_INDEX_WR_ACK 0x7F
-#define MC_DATA 0x007C
-#define HDP_FB_LOCATION 0x0134
-#define DC_LB_MEMORY_SPLIT 0x6520
-#define DC_LB_MEMORY_SPLIT_MASK 0x00000003
-#define DC_LB_MEMORY_SPLIT_SHIFT 0
-#define DC_LB_MEMORY_SPLIT_D1HALF_D2HALF 0
-#define DC_LB_MEMORY_SPLIT_D1_3Q_D2_1Q 1
-#define DC_LB_MEMORY_SPLIT_D1_ONLY 2
-#define DC_LB_MEMORY_SPLIT_D1_1Q_D2_3Q 3
-#define DC_LB_MEMORY_SPLIT_SHIFT_MODE (1 << 2)
-#define DC_LB_DISP1_END_ADR_SHIFT 4
-#define DC_LB_DISP1_END_ADR_MASK 0x00007FF0
-#define D1MODE_PRIORITY_A_CNT 0x6548
-#define MODE_PRIORITY_MARK_MASK 0x00007FFF
-#define MODE_PRIORITY_OFF (1 << 16)
-#define MODE_PRIORITY_ALWAYS_ON (1 << 20)
-#define MODE_PRIORITY_FORCE_MASK (1 << 24)
-#define D1MODE_PRIORITY_B_CNT 0x654C
-#define LB_MAX_REQ_OUTSTANDING 0x6D58
-#define LB_D1_MAX_REQ_OUTSTANDING_MASK 0x0000000F
-#define LB_D1_MAX_REQ_OUTSTANDING_SHIFT 0
-#define LB_D2_MAX_REQ_OUTSTANDING_MASK 0x000F0000
-#define LB_D2_MAX_REQ_OUTSTANDING_SHIFT 16
-#define DCP_CONTROL 0x6C9C
-#define D2MODE_PRIORITY_A_CNT 0x6D48
-#define D2MODE_PRIORITY_B_CNT 0x6D4C
-
-/* MC indirect registers */
-#define MC_STATUS_IDLE (1 << 0)
-#define MC_MISC_CNTL 0x18
-#define DISABLE_GTW (1 << 1)
-#define GART_INDEX_REG_EN (1 << 12)
-#define BLOCK_GFX_D3_EN (1 << 14)
-#define GART_FEATURE_ID 0x2B
-#define HANG_EN (1 << 11)
-#define TLB_ENABLE (1 << 18)
-#define P2P_ENABLE (1 << 19)
-#define GTW_LAC_EN (1 << 25)
-#define LEVEL2_GART (0 << 30)
-#define LEVEL1_GART (1 << 30)
-#define PDC_EN (1 << 31)
-#define GART_BASE 0x2C
-#define GART_CACHE_CNTRL 0x2E
-# define GART_CACHE_INVALIDATE (1 << 0)
-#define MC_STATUS 0x90
-#define MCCFG_FB_LOCATION 0x100
-#define MC_FB_START_MASK 0x0000FFFF
-#define MC_FB_START_SHIFT 0
-#define MC_FB_TOP_MASK 0xFFFF0000
-#define MC_FB_TOP_SHIFT 16
-#define MCCFG_AGP_LOCATION 0x101
-#define MC_AGP_START_MASK 0x0000FFFF
-#define MC_AGP_START_SHIFT 0
-#define MC_AGP_TOP_MASK 0xFFFF0000
-#define MC_AGP_TOP_SHIFT 16
-#define MCCFG_AGP_BASE 0x102
-#define MCCFG_AGP_BASE_2 0x103
-#define MC_INIT_MISC_LAT_TIMER 0x104
-#define MC_DISP0R_INIT_LAT_SHIFT 8
-#define MC_DISP0R_INIT_LAT_MASK 0x00000F00
-#define MC_DISP1R_INIT_LAT_SHIFT 12
-#define MC_DISP1R_INIT_LAT_MASK 0x0000F000
-
-#endif
diff --git a/drivers/gpu/drm/radeon/rv200d.h b/drivers/gpu/drm/radeon/rv200d.h
new file mode 100644
index 000000000000..c5b398330c26
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv200d.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#ifndef __RV200D_H__
+#define __RV200D_H__
+
+#define R_00015C_AGP_BASE_2 0x00015C
+#define S_00015C_AGP_BASE_ADDR_2(x) (((x) & 0xF) << 0)
+#define G_00015C_AGP_BASE_ADDR_2(x) (((x) >> 0) & 0xF)
+#define C_00015C_AGP_BASE_ADDR_2 0xFFFFFFF0
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv250d.h b/drivers/gpu/drm/radeon/rv250d.h
new file mode 100644
index 000000000000..e5a70b06fe1f
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv250d.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#ifndef __RV250D_H__
+#define __RV250D_H__
+
+#define R_00000D_SCLK_CNTL_M6 0x00000D
+#define S_00000D_SCLK_SRC_SEL(x) (((x) & 0x7) << 0)
+#define G_00000D_SCLK_SRC_SEL(x) (((x) >> 0) & 0x7)
+#define C_00000D_SCLK_SRC_SEL 0xFFFFFFF8
+#define S_00000D_CP_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 3)
+#define G_00000D_CP_MAX_DYN_STOP_LAT(x) (((x) >> 3) & 0x1)
+#define C_00000D_CP_MAX_DYN_STOP_LAT 0xFFFFFFF7
+#define S_00000D_HDP_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 4)
+#define G_00000D_HDP_MAX_DYN_STOP_LAT(x) (((x) >> 4) & 0x1)
+#define C_00000D_HDP_MAX_DYN_STOP_LAT 0xFFFFFFEF
+#define S_00000D_TV_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 5)
+#define G_00000D_TV_MAX_DYN_STOP_LAT(x) (((x) >> 5) & 0x1)
+#define C_00000D_TV_MAX_DYN_STOP_LAT 0xFFFFFFDF
+#define S_00000D_E2_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 6)
+#define G_00000D_E2_MAX_DYN_STOP_LAT(x) (((x) >> 6) & 0x1)
+#define C_00000D_E2_MAX_DYN_STOP_LAT 0xFFFFFFBF
+#define S_00000D_SE_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 7)
+#define G_00000D_SE_MAX_DYN_STOP_LAT(x) (((x) >> 7) & 0x1)
+#define C_00000D_SE_MAX_DYN_STOP_LAT 0xFFFFFF7F
+#define S_00000D_IDCT_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 8)
+#define G_00000D_IDCT_MAX_DYN_STOP_LAT(x) (((x) >> 8) & 0x1)
+#define C_00000D_IDCT_MAX_DYN_STOP_LAT 0xFFFFFEFF
+#define S_00000D_VIP_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 9)
+#define G_00000D_VIP_MAX_DYN_STOP_LAT(x) (((x) >> 9) & 0x1)
+#define C_00000D_VIP_MAX_DYN_STOP_LAT 0xFFFFFDFF
+#define S_00000D_RE_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 10)
+#define G_00000D_RE_MAX_DYN_STOP_LAT(x) (((x) >> 10) & 0x1)
+#define C_00000D_RE_MAX_DYN_STOP_LAT 0xFFFFFBFF
+#define S_00000D_PB_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 11)
+#define G_00000D_PB_MAX_DYN_STOP_LAT(x) (((x) >> 11) & 0x1)
+#define C_00000D_PB_MAX_DYN_STOP_LAT 0xFFFFF7FF
+#define S_00000D_TAM_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 12)
+#define G_00000D_TAM_MAX_DYN_STOP_LAT(x) (((x) >> 12) & 0x1)
+#define C_00000D_TAM_MAX_DYN_STOP_LAT 0xFFFFEFFF
+#define S_00000D_TDM_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 13)
+#define G_00000D_TDM_MAX_DYN_STOP_LAT(x) (((x) >> 13) & 0x1)
+#define C_00000D_TDM_MAX_DYN_STOP_LAT 0xFFFFDFFF
+#define S_00000D_RB_MAX_DYN_STOP_LAT(x) (((x) & 0x1) << 14)
+#define G_00000D_RB_MAX_DYN_STOP_LAT(x) (((x) >> 14) & 0x1)
+#define C_00000D_RB_MAX_DYN_STOP_LAT 0xFFFFBFFF
+#define S_00000D_FORCE_DISP2(x) (((x) & 0x1) << 15)
+#define G_00000D_FORCE_DISP2(x) (((x) >> 15) & 0x1)
+#define C_00000D_FORCE_DISP2 0xFFFF7FFF
+#define S_00000D_FORCE_CP(x) (((x) & 0x1) << 16)
+#define G_00000D_FORCE_CP(x) (((x) >> 16) & 0x1)
+#define C_00000D_FORCE_CP 0xFFFEFFFF
+#define S_00000D_FORCE_HDP(x) (((x) & 0x1) << 17)
+#define G_00000D_FORCE_HDP(x) (((x) >> 17) & 0x1)
+#define C_00000D_FORCE_HDP 0xFFFDFFFF
+#define S_00000D_FORCE_DISP1(x) (((x) & 0x1) << 18)
+#define G_00000D_FORCE_DISP1(x) (((x) >> 18) & 0x1)
+#define C_00000D_FORCE_DISP1 0xFFFBFFFF
+#define S_00000D_FORCE_TOP(x) (((x) & 0x1) << 19)
+#define G_00000D_FORCE_TOP(x) (((x) >> 19) & 0x1)
+#define C_00000D_FORCE_TOP 0xFFF7FFFF
+#define S_00000D_FORCE_E2(x) (((x) & 0x1) << 20)
+#define G_00000D_FORCE_E2(x) (((x) >> 20) & 0x1)
+#define C_00000D_FORCE_E2 0xFFEFFFFF
+#define S_00000D_FORCE_SE(x) (((x) & 0x1) << 21)
+#define G_00000D_FORCE_SE(x) (((x) >> 21) & 0x1)
+#define C_00000D_FORCE_SE 0xFFDFFFFF
+#define S_00000D_FORCE_IDCT(x) (((x) & 0x1) << 22)
+#define G_00000D_FORCE_IDCT(x) (((x) >> 22) & 0x1)
+#define C_00000D_FORCE_IDCT 0xFFBFFFFF
+#define S_00000D_FORCE_VIP(x) (((x) & 0x1) << 23)
+#define G_00000D_FORCE_VIP(x) (((x) >> 23) & 0x1)
+#define C_00000D_FORCE_VIP 0xFF7FFFFF
+#define S_00000D_FORCE_RE(x) (((x) & 0x1) << 24)
+#define G_00000D_FORCE_RE(x) (((x) >> 24) & 0x1)
+#define C_00000D_FORCE_RE 0xFEFFFFFF
+#define S_00000D_FORCE_PB(x) (((x) & 0x1) << 25)
+#define G_00000D_FORCE_PB(x) (((x) >> 25) & 0x1)
+#define C_00000D_FORCE_PB 0xFDFFFFFF
+#define S_00000D_FORCE_TAM(x) (((x) & 0x1) << 26)
+#define G_00000D_FORCE_TAM(x) (((x) >> 26) & 0x1)
+#define C_00000D_FORCE_TAM 0xFBFFFFFF
+#define S_00000D_FORCE_TDM(x) (((x) & 0x1) << 27)
+#define G_00000D_FORCE_TDM(x) (((x) >> 27) & 0x1)
+#define C_00000D_FORCE_TDM 0xF7FFFFFF
+#define S_00000D_FORCE_RB(x) (((x) & 0x1) << 28)
+#define G_00000D_FORCE_RB(x) (((x) >> 28) & 0x1)
+#define C_00000D_FORCE_RB 0xEFFFFFFF
+#define S_00000D_FORCE_TV_SCLK(x) (((x) & 0x1) << 29)
+#define G_00000D_FORCE_TV_SCLK(x) (((x) >> 29) & 0x1)
+#define C_00000D_FORCE_TV_SCLK 0xDFFFFFFF
+#define S_00000D_FORCE_SUBPIC(x) (((x) & 0x1) << 30)
+#define G_00000D_FORCE_SUBPIC(x) (((x) >> 30) & 0x1)
+#define C_00000D_FORCE_SUBPIC 0xBFFFFFFF
+#define S_00000D_FORCE_OV0(x) (((x) & 0x1) << 31)
+#define G_00000D_FORCE_OV0(x) (((x) >> 31) & 0x1)
+#define C_00000D_FORCE_OV0 0x7FFFFFFF
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv350d.h b/drivers/gpu/drm/radeon/rv350d.h
new file mode 100644
index 000000000000..c75c5ed9e654
--- /dev/null
+++ b/drivers/gpu/drm/radeon/rv350d.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Dave Airlie
+ * Alex Deucher
+ * Jerome Glisse
+ */
+#ifndef __RV350D_H__
+#define __RV350D_H__
+
+/* RV350, RV380 registers */
+/* #define R_00000D_SCLK_CNTL 0x00000D */
+#define S_00000D_FORCE_VAP(x) (((x) & 0x1) << 21)
+#define G_00000D_FORCE_VAP(x) (((x) >> 21) & 0x1)
+#define C_00000D_FORCE_VAP 0xFFDFFFFF
+#define S_00000D_FORCE_SR(x) (((x) & 0x1) << 25)
+#define G_00000D_FORCE_SR(x) (((x) >> 25) & 0x1)
+#define C_00000D_FORCE_SR 0xFDFFFFFF
+#define S_00000D_FORCE_PX(x) (((x) & 0x1) << 26)
+#define G_00000D_FORCE_PX(x) (((x) >> 26) & 0x1)
+#define C_00000D_FORCE_PX 0xFBFFFFFF
+#define S_00000D_FORCE_TX(x) (((x) & 0x1) << 27)
+#define G_00000D_FORCE_TX(x) (((x) >> 27) & 0x1)
+#define C_00000D_FORCE_TX 0xF7FFFFFF
+#define S_00000D_FORCE_US(x) (((x) & 0x1) << 28)
+#define G_00000D_FORCE_US(x) (((x) >> 28) & 0x1)
+#define C_00000D_FORCE_US 0xEFFFFFFF
+#define S_00000D_FORCE_SU(x) (((x) & 0x1) << 30)
+#define G_00000D_FORCE_SU(x) (((x) >> 30) & 0x1)
+#define C_00000D_FORCE_SU 0xBFFFFFFF
+
+#endif
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index e53b5ca7a253..41a34c23e6d8 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -478,7 +478,7 @@ static int rv515_startup(struct radeon_device *rdev)
}
/* Enable IRQ */
rdev->irq.sw_int = true;
- r100_irq_set(rdev);
+ rs600_irq_set(rdev);
/* 1M ring buffer */
r = r100_cp_init(rdev, 1024 * 1024);
if (r) {
@@ -520,7 +520,7 @@ int rv515_suspend(struct radeon_device *rdev)
{
r100_cp_disable(rdev);
r100_wb_disable(rdev);
- r100_irq_disable(rdev);
+ rs600_irq_disable(rdev);
if (rdev->flags & RADEON_IS_PCIE)
rv370_pcie_gart_disable(rdev);
return 0;
@@ -553,7 +553,6 @@ int rv515_init(struct radeon_device *rdev)
{
int r;
- rdev->new_init_path = true;
/* Initialize scratch registers */
radeon_scratch_init(rdev);
/* Initialize surface registers */
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index e0b97d161397..595ac638039d 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -75,7 +75,7 @@ int rv770_pcie_gart_enable(struct radeon_device *rdev)
WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp);
WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp);
WREG32(VM_CONTEXT0_PAGE_TABLE_START_ADDR, rdev->mc.gtt_start >> 12);
- WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, (rdev->mc.gtt_end - 1) >> 12);
+ WREG32(VM_CONTEXT0_PAGE_TABLE_END_ADDR, rdev->mc.gtt_end >> 12);
WREG32(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR, rdev->gart.table_addr >> 12);
WREG32(VM_CONTEXT0_CNTL, ENABLE_CONTEXT | PAGE_TABLE_DEPTH(0) |
RANGE_PROTECTION_FAULT_ENABLE_DEFAULT);
@@ -126,17 +126,36 @@ void rv770_pcie_gart_fini(struct radeon_device *rdev)
}
-/*
- * MC
- */
-static void rv770_mc_resume(struct radeon_device *rdev)
+void rv770_agp_enable(struct radeon_device *rdev)
{
- u32 d1vga_control, d2vga_control;
- u32 vga_render_control, vga_hdp_control;
- u32 d1crtc_control, d2crtc_control;
- u32 new_d1grph_primary, new_d1grph_secondary;
- u32 new_d2grph_primary, new_d2grph_secondary;
- u64 old_vram_start;
+ u32 tmp;
+ int i;
+
+ /* Setup L2 cache */
+ WREG32(VM_L2_CNTL, ENABLE_L2_CACHE | ENABLE_L2_FRAGMENT_PROCESSING |
+ ENABLE_L2_PTE_CACHE_LRU_UPDATE_BY_WRITE |
+ EFFECTIVE_L2_QUEUE_SIZE(7));
+ WREG32(VM_L2_CNTL2, 0);
+ WREG32(VM_L2_CNTL3, BANK_SELECT(0) | CACHE_UPDATE_MODE(2));
+ /* Setup TLB control */
+ tmp = ENABLE_L1_TLB | ENABLE_L1_FRAGMENT_PROCESSING |
+ SYSTEM_ACCESS_MODE_NOT_IN_SYS |
+ SYSTEM_APERTURE_UNMAPPED_ACCESS_PASS_THRU |
+ EFFECTIVE_L1_TLB_SIZE(5) | EFFECTIVE_L1_QUEUE_SIZE(5);
+ WREG32(MC_VM_MD_L1_TLB0_CNTL, tmp);
+ WREG32(MC_VM_MD_L1_TLB1_CNTL, tmp);
+ WREG32(MC_VM_MD_L1_TLB2_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB0_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB1_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB2_CNTL, tmp);
+ WREG32(MC_VM_MB_L1_TLB3_CNTL, tmp);
+ for (i = 0; i < 7; i++)
+ WREG32(VM_CONTEXT0_CNTL + (i * 4), 0);
+}
+
+static void rv770_mc_program(struct radeon_device *rdev)
+{
+ struct rv515_mc_save save;
u32 tmp;
int i, j;
@@ -150,53 +169,42 @@ static void rv770_mc_resume(struct radeon_device *rdev)
}
WREG32(HDP_REG_COHERENCY_FLUSH_CNTL, 0);
- d1vga_control = RREG32(D1VGA_CONTROL);
- d2vga_control = RREG32(D2VGA_CONTROL);
- vga_render_control = RREG32(VGA_RENDER_CONTROL);
- vga_hdp_control = RREG32(VGA_HDP_CONTROL);
- d1crtc_control = RREG32(D1CRTC_CONTROL);
- d2crtc_control = RREG32(D2CRTC_CONTROL);
- old_vram_start = (u64)(RREG32(MC_VM_FB_LOCATION) & 0xFFFF) << 24;
- new_d1grph_primary = RREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS);
- new_d1grph_secondary = RREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS);
- new_d1grph_primary += rdev->mc.vram_start - old_vram_start;
- new_d1grph_secondary += rdev->mc.vram_start - old_vram_start;
- new_d2grph_primary = RREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS);
- new_d2grph_secondary = RREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS);
- new_d2grph_primary += rdev->mc.vram_start - old_vram_start;
- new_d2grph_secondary += rdev->mc.vram_start - old_vram_start;
-
- /* Stop all video */
- WREG32(D1VGA_CONTROL, 0);
- WREG32(D2VGA_CONTROL, 0);
- WREG32(VGA_RENDER_CONTROL, 0);
- WREG32(D1CRTC_UPDATE_LOCK, 1);
- WREG32(D2CRTC_UPDATE_LOCK, 1);
- WREG32(D1CRTC_CONTROL, 0);
- WREG32(D2CRTC_CONTROL, 0);
- WREG32(D1CRTC_UPDATE_LOCK, 0);
- WREG32(D2CRTC_UPDATE_LOCK, 0);
-
- mdelay(1);
+ rv515_mc_stop(rdev, &save);
if (r600_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "[drm] MC not idle !\n");
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
-
/* Lockout access through VGA aperture*/
WREG32(VGA_HDP_CONTROL, VGA_MEMORY_DISABLE);
-
/* Update configuration */
- WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR, rdev->mc.vram_start >> 12);
- WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, (rdev->mc.vram_end - 1) >> 12);
+ if (rdev->flags & RADEON_IS_AGP) {
+ if (rdev->mc.vram_start < rdev->mc.gtt_start) {
+ /* VRAM before AGP */
+ WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+ rdev->mc.vram_start >> 12);
+ WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+ rdev->mc.gtt_end >> 12);
+ } else {
+ /* VRAM after AGP */
+ WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+ rdev->mc.gtt_start >> 12);
+ WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+ rdev->mc.vram_end >> 12);
+ }
+ } else {
+ WREG32(MC_VM_SYSTEM_APERTURE_LOW_ADDR,
+ rdev->mc.vram_start >> 12);
+ WREG32(MC_VM_SYSTEM_APERTURE_HIGH_ADDR,
+ rdev->mc.vram_end >> 12);
+ }
WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0);
- tmp = (((rdev->mc.vram_end - 1) >> 24) & 0xFFFF) << 16;
+ tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16;
tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF);
WREG32(MC_VM_FB_LOCATION, tmp);
WREG32(HDP_NONSURFACE_BASE, (rdev->mc.vram_start >> 8));
WREG32(HDP_NONSURFACE_INFO, (2 << 7));
WREG32(HDP_NONSURFACE_SIZE, (rdev->mc.mc_vram_size - 1) | 0x3FF);
if (rdev->flags & RADEON_IS_AGP) {
- WREG32(MC_VM_AGP_TOP, (rdev->mc.gtt_end - 1) >> 16);
+ WREG32(MC_VM_AGP_TOP, rdev->mc.gtt_end >> 16);
WREG32(MC_VM_AGP_BOT, rdev->mc.gtt_start >> 16);
WREG32(MC_VM_AGP_BASE, rdev->mc.agp_base >> 22);
} else {
@@ -204,31 +212,10 @@ static void rv770_mc_resume(struct radeon_device *rdev)
WREG32(MC_VM_AGP_TOP, 0x0FFFFFFF);
WREG32(MC_VM_AGP_BOT, 0x0FFFFFFF);
}
- WREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS, new_d1grph_primary);
- WREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS, new_d1grph_secondary);
- WREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS, new_d2grph_primary);
- WREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS, new_d2grph_secondary);
- WREG32(VGA_MEMORY_BASE_ADDRESS, rdev->mc.vram_start);
-
- /* Unlock host access */
- WREG32(VGA_HDP_CONTROL, vga_hdp_control);
-
- mdelay(1);
if (r600_mc_wait_for_idle(rdev)) {
- printk(KERN_WARNING "[drm] MC not idle !\n");
+ dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
}
-
- /* Restore video state */
- WREG32(D1CRTC_UPDATE_LOCK, 1);
- WREG32(D2CRTC_UPDATE_LOCK, 1);
- WREG32(D1CRTC_CONTROL, d1crtc_control);
- WREG32(D2CRTC_CONTROL, d2crtc_control);
- WREG32(D1CRTC_UPDATE_LOCK, 0);
- WREG32(D2CRTC_UPDATE_LOCK, 0);
- WREG32(D1VGA_CONTROL, d1vga_control);
- WREG32(D2VGA_CONTROL, d2vga_control);
- WREG32(VGA_RENDER_CONTROL, vga_render_control);
-
+ rv515_mc_resume(rdev, &save);
/* we need to own VRAM, so turn off the VGA renderer here
* to stop it overwriting our objects */
rv515_vga_render_disable(rdev);
@@ -840,9 +827,9 @@ int rv770_mc_init(struct radeon_device *rdev)
rdev->mc.gtt_size = radeon_gart_size * 1024 * 1024;
}
rdev->mc.vram_start = rdev->mc.vram_location;
- rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size;
+ rdev->mc.vram_end = rdev->mc.vram_location + rdev->mc.mc_vram_size - 1;
rdev->mc.gtt_start = rdev->mc.gtt_location;
- rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size;
+ rdev->mc.gtt_end = rdev->mc.gtt_location + rdev->mc.gtt_size - 1;
/* FIXME: we should enforce default clock in case GPU is not in
* default setup
*/
@@ -861,11 +848,14 @@ static int rv770_startup(struct radeon_device *rdev)
{
int r;
- radeon_gpu_reset(rdev);
- rv770_mc_resume(rdev);
- r = rv770_pcie_gart_enable(rdev);
- if (r)
- return r;
+ rv770_mc_program(rdev);
+ if (rdev->flags & RADEON_IS_AGP) {
+ rv770_agp_enable(rdev);
+ } else {
+ r = rv770_pcie_gart_enable(rdev);
+ if (r)
+ return r;
+ }
rv770_gpu_init(rdev);
r = radeon_object_pin(rdev->r600_blit.shader_obj, RADEON_GEM_DOMAIN_VRAM,
@@ -884,9 +874,8 @@ static int rv770_startup(struct radeon_device *rdev)
r = r600_cp_resume(rdev);
if (r)
return r;
- r = r600_wb_init(rdev);
- if (r)
- return r;
+ /* write back buffer are not vital so don't worry about failure */
+ r600_wb_enable(rdev);
return 0;
}
@@ -894,15 +883,12 @@ int rv770_resume(struct radeon_device *rdev)
{
int r;
- if (radeon_gpu_reset(rdev)) {
- /* FIXME: what do we want to do here ? */
- }
+ /* Do not reset GPU before posting, on rv770 hw unlike on r500 hw,
+ * posting will perform necessary task to bring back GPU into good
+ * shape.
+ */
/* post card */
- if (rdev->is_atom_bios) {
- atom_asic_init(rdev->mode_info.atom_context);
- } else {
- radeon_combios_asic_init(rdev->ddev);
- }
+ atom_asic_init(rdev->mode_info.atom_context);
/* Initialize clocks */
r = radeon_clocks_init(rdev);
if (r) {
@@ -915,7 +901,7 @@ int rv770_resume(struct radeon_device *rdev)
return r;
}
- r = radeon_ib_test(rdev);
+ r = r600_ib_test(rdev);
if (r) {
DRM_ERROR("radeon: failled testing IB (%d).\n", r);
return r;
@@ -929,8 +915,8 @@ int rv770_suspend(struct radeon_device *rdev)
/* FIXME: we should wait for ring to be empty */
r700_cp_stop(rdev);
rdev->cp.ready = false;
+ r600_wb_disable(rdev);
rv770_pcie_gart_disable(rdev);
-
/* unpin shaders bo */
radeon_object_unpin(rdev->r600_blit.shader_obj);
return 0;
@@ -946,7 +932,6 @@ int rv770_init(struct radeon_device *rdev)
{
int r;
- rdev->new_init_path = true;
r = radeon_dummy_page_init(rdev);
if (r)
return r;
@@ -960,8 +945,10 @@ int rv770_init(struct radeon_device *rdev)
return -EINVAL;
}
/* Must be an ATOMBIOS */
- if (!rdev->is_atom_bios)
+ if (!rdev->is_atom_bios) {
+ dev_err(rdev->dev, "Expecting atombios for R600 GPU\n");
return -EINVAL;
+ }
r = radeon_atombios_init(rdev);
if (r)
return r;
@@ -983,15 +970,8 @@ int rv770_init(struct radeon_device *rdev)
if (r)
return r;
r = rv770_mc_init(rdev);
- if (r) {
- if (rdev->flags & RADEON_IS_AGP) {
- /* Retry with disabling AGP */
- rv770_fini(rdev);
- rdev->flags &= ~RADEON_IS_AGP;
- return rv770_init(rdev);
- }
+ if (r)
return r;
- }
/* Memory manager */
r = radeon_object_init(rdev);
if (r)
@@ -1020,12 +1000,10 @@ int rv770_init(struct radeon_device *rdev)
r = rv770_startup(rdev);
if (r) {
- if (rdev->flags & RADEON_IS_AGP) {
- /* Retry with disabling AGP */
- rv770_fini(rdev);
- rdev->flags &= ~RADEON_IS_AGP;
- return rv770_init(rdev);
- }
+ rv770_suspend(rdev);
+ r600_wb_fini(rdev);
+ radeon_ring_fini(rdev);
+ rv770_pcie_gart_fini(rdev);
rdev->accel_working = false;
}
if (rdev->accel_working) {
@@ -1034,7 +1012,7 @@ int rv770_init(struct radeon_device *rdev)
DRM_ERROR("radeon: failled initializing IB pool (%d).\n", r);
rdev->accel_working = false;
}
- r = radeon_ib_test(rdev);
+ r = r600_ib_test(rdev);
if (r) {
DRM_ERROR("radeon: failled testing IB (%d).\n", r);
rdev->accel_working = false;
@@ -1049,20 +1027,15 @@ void rv770_fini(struct radeon_device *rdev)
r600_blit_fini(rdev);
radeon_ring_fini(rdev);
+ r600_wb_fini(rdev);
rv770_pcie_gart_fini(rdev);
radeon_gem_fini(rdev);
radeon_fence_driver_fini(rdev);
radeon_clocks_fini(rdev);
-#if __OS_HAS_AGP
if (rdev->flags & RADEON_IS_AGP)
radeon_agp_fini(rdev);
-#endif
radeon_object_fini(rdev);
- if (rdev->is_atom_bios) {
- radeon_atombios_fini(rdev);
- } else {
- radeon_combios_fini(rdev);
- }
+ radeon_atombios_fini(rdev);
kfree(rdev->bios);
rdev->bios = NULL;
radeon_dummy_page_fini(rdev);
diff --git a/drivers/gpu/drm/ttm/ttm_global.c b/drivers/gpu/drm/ttm/ttm_global.c
index 541744d00d3e..b17007178a36 100644
--- a/drivers/gpu/drm/ttm/ttm_global.c
+++ b/drivers/gpu/drm/ttm/ttm_global.c
@@ -82,8 +82,8 @@ int ttm_global_item_ref(struct ttm_global_reference *ref)
if (unlikely(ret != 0))
goto out_err;
- ++item->refcount;
}
+ ++item->refcount;
ref->object = item->object;
object = item->object;
mutex_unlock(&item->mutex);
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index be34d32906bd..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"
@@ -1066,7 +1064,7 @@ EXPORT_SYMBOL_GPL(hid_report_raw_event);
* @type: HID report type (HID_*_REPORT)
* @data: report contents
* @size: size of data parameter
- * @interrupt: called from atomic?
+ * @interrupt: distinguish between interrupt and control transfers
*
* This is data entry for lower layers.
*/
@@ -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-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/hid-twinhan.c b/drivers/hid/hid-twinhan.c
index b05f602c051e..c40afc57fc8f 100644
--- a/drivers/hid/hid-twinhan.c
+++ b/drivers/hid/hid-twinhan.c
@@ -132,12 +132,12 @@ static struct hid_driver twinhan_driver = {
.input_mapping = twinhan_input_mapping,
};
-static int twinhan_init(void)
+static int __init twinhan_init(void)
{
return hid_register_driver(&twinhan_driver);
}
-static void twinhan_exit(void)
+static void __exit twinhan_exit(void)
{
hid_unregister_driver(&twinhan_driver);
}
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index ba05275e5104..cdd136942bca 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -48,10 +48,9 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
char *report;
DECLARE_WAITQUEUE(wait, current);
- while (ret == 0) {
-
- mutex_lock(&list->read_mutex);
+ mutex_lock(&list->read_mutex);
+ while (ret == 0) {
if (list->head == list->tail) {
add_wait_queue(&list->hidraw->wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
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/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 6857560144bd..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
@@ -675,7 +684,7 @@ config SENSORS_SHT15
config SENSORS_S3C
tristate "S3C24XX/S3C64XX Inbuilt ADC"
- depends on ARCH_S3C2410 || ARCH_S3C64XX
+ depends on ARCH_S3C2410
help
If you say yes here you get support for the on-board ADCs of
the Samsung S3C24XX or S3C64XX series of SoC
@@ -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/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
index fe4fa29c9219..5a3ee00c0e7d 100644
--- a/drivers/hwmon/asus_atk0110.c
+++ b/drivers/hwmon/asus_atk0110.c
@@ -35,18 +35,22 @@
#define METHOD_OLD_ENUM_FAN "FSIF"
#define ATK_MUX_HWMON 0x00000006ULL
+#define ATK_MUX_MGMT 0x00000011ULL
#define ATK_CLASS_MASK 0xff000000ULL
#define ATK_CLASS_FREQ_CTL 0x03000000ULL
#define ATK_CLASS_FAN_CTL 0x04000000ULL
#define ATK_CLASS_HWMON 0x06000000ULL
+#define ATK_CLASS_MGMT 0x11000000ULL
#define ATK_TYPE_MASK 0x00ff0000ULL
#define HWMON_TYPE_VOLT 0x00020000ULL
#define HWMON_TYPE_TEMP 0x00030000ULL
#define HWMON_TYPE_FAN 0x00040000ULL
-#define HWMON_SENSOR_ID_MASK 0x0000ffffULL
+#define ATK_ELEMENT_ID_MASK 0x0000ffffULL
+
+#define ATK_EC_ID 0x11060004ULL
enum atk_pack_member {
HWMON_PACK_FLAGS,
@@ -89,6 +93,9 @@ struct atk_data {
/* new inteface */
acpi_handle enumerate_handle;
acpi_handle read_handle;
+ acpi_handle write_handle;
+
+ bool disable_ec;
int voltage_count;
int temperature_count;
@@ -129,9 +136,22 @@ struct atk_sensor_data {
char const *acpi_name;
};
-struct atk_acpi_buffer_u64 {
- union acpi_object buf;
- u64 value;
+/* Return buffer format:
+ * [0-3] "value" is valid flag
+ * [4-7] value
+ * [8- ] unknown stuff on newer mobos
+ */
+struct atk_acpi_ret_buffer {
+ u32 flags;
+ u32 value;
+ u8 data[];
+};
+
+/* Input buffer used for GITM and SITM methods */
+struct atk_acpi_input_buf {
+ u32 id;
+ u32 param1;
+ u32 param2;
};
static int atk_add(struct acpi_device *device);
@@ -439,52 +459,147 @@ static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value)
return 0;
}
-static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
+static union acpi_object *atk_ggrp(struct atk_data *data, u16 mux)
{
- struct atk_data *data = sensor->data;
struct device *dev = &data->acpi_dev->dev;
+ struct acpi_buffer buf;
+ acpi_status ret;
struct acpi_object_list params;
- struct acpi_buffer ret;
union acpi_object id;
- struct atk_acpi_buffer_u64 tmp;
- acpi_status status;
+ union acpi_object *pack;
id.type = ACPI_TYPE_INTEGER;
- id.integer.value = sensor->id;
-
+ id.integer.value = mux;
params.count = 1;
params.pointer = &id;
- tmp.buf.type = ACPI_TYPE_BUFFER;
- tmp.buf.buffer.pointer = (u8 *)&tmp.value;
- tmp.buf.buffer.length = sizeof(u64);
- ret.length = sizeof(tmp);
- ret.pointer = &tmp;
+ buf.length = ACPI_ALLOCATE_BUFFER;
+ ret = acpi_evaluate_object(data->enumerate_handle, NULL, &params, &buf);
+ if (ret != AE_OK) {
+ dev_err(dev, "GGRP[%#x] ACPI exception: %s\n", mux,
+ acpi_format_exception(ret));
+ return ERR_PTR(-EIO);
+ }
+ pack = buf.pointer;
+ if (pack->type != ACPI_TYPE_PACKAGE) {
+ /* Execution was successful, but the id was not found */
+ ACPI_FREE(pack);
+ return ERR_PTR(-ENOENT);
+ }
+
+ if (pack->package.count < 1) {
+ dev_err(dev, "GGRP[%#x] package is too small\n", mux);
+ ACPI_FREE(pack);
+ return ERR_PTR(-EIO);
+ }
+ return pack;
+}
+
+static union acpi_object *atk_gitm(struct atk_data *data, u64 id)
+{
+ struct device *dev = &data->acpi_dev->dev;
+ struct atk_acpi_input_buf buf;
+ union acpi_object tmp;
+ struct acpi_object_list params;
+ struct acpi_buffer ret;
+ union acpi_object *obj;
+ acpi_status status;
+
+ buf.id = id;
+ buf.param1 = 0;
+ buf.param2 = 0;
+ tmp.type = ACPI_TYPE_BUFFER;
+ tmp.buffer.pointer = (u8 *)&buf;
+ tmp.buffer.length = sizeof(buf);
+
+ params.count = 1;
+ params.pointer = (void *)&tmp;
+
+ ret.length = ACPI_ALLOCATE_BUFFER;
status = acpi_evaluate_object_typed(data->read_handle, NULL, &params,
&ret, ACPI_TYPE_BUFFER);
if (status != AE_OK) {
- dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
+ dev_warn(dev, "GITM[%#llx] ACPI exception: %s\n", id,
acpi_format_exception(status));
- return -EIO;
+ return ERR_PTR(-EIO);
+ }
+ obj = ret.pointer;
+
+ /* Sanity check */
+ if (obj->buffer.length < 8) {
+ dev_warn(dev, "Unexpected ASBF length: %u\n",
+ obj->buffer.length);
+ ACPI_FREE(obj);
+ return ERR_PTR(-EIO);
}
+ return obj;
+}
- /* Return buffer format:
- * [0-3] "value" is valid flag
- * [4-7] value
- */
- if (!(tmp.value & 0xffffffff)) {
+static union acpi_object *atk_sitm(struct atk_data *data,
+ struct atk_acpi_input_buf *buf)
+{
+ struct device *dev = &data->acpi_dev->dev;
+ struct acpi_object_list params;
+ union acpi_object tmp;
+ struct acpi_buffer ret;
+ union acpi_object *obj;
+ acpi_status status;
+
+ tmp.type = ACPI_TYPE_BUFFER;
+ tmp.buffer.pointer = (u8 *)buf;
+ tmp.buffer.length = sizeof(*buf);
+
+ params.count = 1;
+ params.pointer = &tmp;
+
+ ret.length = ACPI_ALLOCATE_BUFFER;
+ status = acpi_evaluate_object_typed(data->write_handle, NULL, &params,
+ &ret, ACPI_TYPE_BUFFER);
+ if (status != AE_OK) {
+ dev_warn(dev, "SITM[%#x] ACPI exception: %s\n", buf->id,
+ acpi_format_exception(status));
+ return ERR_PTR(-EIO);
+ }
+ obj = ret.pointer;
+
+ /* Sanity check */
+ if (obj->buffer.length < 8) {
+ dev_warn(dev, "Unexpected ASBF length: %u\n",
+ obj->buffer.length);
+ ACPI_FREE(obj);
+ return ERR_PTR(-EIO);
+ }
+ return obj;
+}
+
+static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
+{
+ struct atk_data *data = sensor->data;
+ struct device *dev = &data->acpi_dev->dev;
+ union acpi_object *obj;
+ struct atk_acpi_ret_buffer *buf;
+ int err = 0;
+
+ obj = atk_gitm(data, sensor->id);
+ if (IS_ERR(obj))
+ return PTR_ERR(obj);
+
+ buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
+ if (buf->flags == 0) {
/* The reading is not valid, possible causes:
* - sensor failure
* - enumeration was FUBAR (and we didn't notice)
*/
- dev_info(dev, "Failure: %#llx\n", tmp.value);
- return -EIO;
+ dev_warn(dev, "Read failed, sensor = %#llx\n", sensor->id);
+ err = -EIO;
+ goto out;
}
- *value = (tmp.value & 0xffffffff00000000ULL) >> 32;
-
- return 0;
+ *value = buf->value;
+out:
+ ACPI_FREE(obj);
+ return err;
}
static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
@@ -713,43 +828,141 @@ cleanup:
return ret;
}
-static int atk_enumerate_new_hwmon(struct atk_data *data)
+static int atk_ec_present(struct atk_data *data)
{
struct device *dev = &data->acpi_dev->dev;
- struct acpi_buffer buf;
- acpi_status ret;
- struct acpi_object_list params;
- union acpi_object id;
union acpi_object *pack;
- int err;
+ union acpi_object *ec;
+ int ret;
int i;
- dev_dbg(dev, "Enumerating hwmon sensors\n");
+ pack = atk_ggrp(data, ATK_MUX_MGMT);
+ if (IS_ERR(pack)) {
+ if (PTR_ERR(pack) == -ENOENT) {
+ /* The MGMT class does not exists - that's ok */
+ dev_dbg(dev, "Class %#llx not found\n", ATK_MUX_MGMT);
+ return 0;
+ }
+ return PTR_ERR(pack);
+ }
- id.type = ACPI_TYPE_INTEGER;
- id.integer.value = ATK_MUX_HWMON;
- params.count = 1;
- params.pointer = &id;
+ /* Search the EC */
+ ec = NULL;
+ for (i = 0; i < pack->package.count; i++) {
+ union acpi_object *obj = &pack->package.elements[i];
+ union acpi_object *id;
- buf.length = ACPI_ALLOCATE_BUFFER;
- ret = acpi_evaluate_object_typed(data->enumerate_handle, NULL, &params,
- &buf, ACPI_TYPE_PACKAGE);
- if (ret != AE_OK) {
- dev_warn(dev, METHOD_ENUMERATE ": ACPI exception: %s\n",
- acpi_format_exception(ret));
- return -ENODEV;
+ if (obj->type != ACPI_TYPE_PACKAGE)
+ continue;
+
+ id = &obj->package.elements[0];
+ if (id->type != ACPI_TYPE_INTEGER)
+ continue;
+
+ if (id->integer.value == ATK_EC_ID) {
+ ec = obj;
+ break;
+ }
}
- /* Result must be a package */
- pack = buf.pointer;
+ ret = (ec != NULL);
+ if (!ret)
+ /* The system has no EC */
+ dev_dbg(dev, "EC not found\n");
- if (pack->package.count < 1) {
- dev_dbg(dev, "%s: hwmon package is too small: %d\n", __func__,
- pack->package.count);
- err = -EINVAL;
- goto out;
+ ACPI_FREE(pack);
+ return ret;
+}
+
+static int atk_ec_enabled(struct atk_data *data)
+{
+ struct device *dev = &data->acpi_dev->dev;
+ union acpi_object *obj;
+ struct atk_acpi_ret_buffer *buf;
+ int err;
+
+ obj = atk_gitm(data, ATK_EC_ID);
+ if (IS_ERR(obj)) {
+ dev_err(dev, "Unable to query EC status\n");
+ return PTR_ERR(obj);
+ }
+ buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
+
+ if (buf->flags == 0) {
+ dev_err(dev, "Unable to query EC status\n");
+ err = -EIO;
+ } else {
+ err = (buf->value != 0);
+ dev_dbg(dev, "EC is %sabled\n",
+ err ? "en" : "dis");
+ }
+
+ ACPI_FREE(obj);
+ return err;
+}
+
+static int atk_ec_ctl(struct atk_data *data, int enable)
+{
+ struct device *dev = &data->acpi_dev->dev;
+ union acpi_object *obj;
+ struct atk_acpi_input_buf sitm;
+ struct atk_acpi_ret_buffer *ec_ret;
+ int err = 0;
+
+ sitm.id = ATK_EC_ID;
+ sitm.param1 = enable;
+ sitm.param2 = 0;
+
+ obj = atk_sitm(data, &sitm);
+ if (IS_ERR(obj)) {
+ dev_err(dev, "Failed to %sable the EC\n",
+ enable ? "en" : "dis");
+ return PTR_ERR(obj);
+ }
+ ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
+ if (ec_ret->flags == 0) {
+ dev_err(dev, "Failed to %sable the EC\n",
+ enable ? "en" : "dis");
+ err = -EIO;
+ } else {
+ dev_info(dev, "EC %sabled\n",
+ enable ? "en" : "dis");
+ }
+
+ ACPI_FREE(obj);
+ return err;
+}
+
+static int atk_enumerate_new_hwmon(struct atk_data *data)
+{
+ struct device *dev = &data->acpi_dev->dev;
+ union acpi_object *pack;
+ int err;
+ int i;
+
+ err = atk_ec_present(data);
+ if (err < 0)
+ return err;
+ if (err) {
+ err = atk_ec_enabled(data);
+ if (err < 0)
+ return err;
+ /* If the EC was disabled we will disable it again on unload */
+ data->disable_ec = err;
+
+ err = atk_ec_ctl(data, 1);
+ if (err) {
+ data->disable_ec = false;
+ return err;
+ }
}
+ dev_dbg(dev, "Enumerating hwmon sensors\n");
+
+ pack = atk_ggrp(data, ATK_MUX_HWMON);
+ if (IS_ERR(pack))
+ return PTR_ERR(pack);
+
for (i = 0; i < pack->package.count; i++) {
union acpi_object *obj = &pack->package.elements[i];
@@ -758,8 +971,7 @@ static int atk_enumerate_new_hwmon(struct atk_data *data)
err = data->voltage_count + data->temperature_count + data->fan_count;
-out:
- ACPI_FREE(buf.pointer);
+ ACPI_FREE(pack);
return err;
}
@@ -895,6 +1107,15 @@ static int atk_check_new_if(struct atk_data *data)
}
data->read_handle = ret;
+ /* De-multiplexer (write) */
+ status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret);
+ if (status != AE_OK) {
+ dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
+ acpi_format_exception(status));
+ return -ENODEV;
+ }
+ data->write_handle = ret;
+
return 0;
}
@@ -915,6 +1136,7 @@ static int atk_add(struct acpi_device *device)
data->acpi_dev = device;
data->atk_handle = device->handle;
INIT_LIST_HEAD(&data->sensor_list);
+ data->disable_ec = false;
buf.length = ACPI_ALLOCATE_BUFFER;
ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL,
@@ -973,6 +1195,8 @@ static int atk_add(struct acpi_device *device)
cleanup:
atk_free_sensors(data);
out:
+ if (data->disable_ec)
+ atk_ec_ctl(data, 0);
kfree(data);
return err;
}
@@ -988,6 +1212,11 @@ static int atk_remove(struct acpi_device *device, int type)
atk_free_sensors(data);
hwmon_device_unregister(data->hwmon_dev);
+ if (data->disable_ec) {
+ if (atk_ec_ctl(data, 0))
+ dev_err(&device->dev, "Failed to disable EC\n");
+ }
+
kfree(data);
return 0;
diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index 2c2cb1ec94c5..846ca631140a 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -2201,33 +2201,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..0cae0cfed3c3 100644
--- a/drivers/hwmon/fschmd.c
+++ b/drivers/hwmon/fschmd.c
@@ -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/lis3lv02d_spi.c b/drivers/hwmon/lis3lv02d_spi.c
index ecd739534f6a..82b16808a274 100644
--- a/drivers/hwmon/lis3lv02d_spi.c
+++ b/drivers/hwmon/lis3lv02d_spi.c
@@ -83,7 +83,8 @@ static int __devexit lis302dl_spi_remove(struct spi_device *spi)
struct lis3lv02d *lis3 = spi_get_drvdata(spi);
lis3lv02d_joystick_disable();
lis3lv02d_poweroff(lis3);
- return 0;
+
+ return lis3lv02d_remove_fs(&lis3_dev);
}
#ifdef CONFIG_PM
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..ae53a7d94c4e
--- /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(&pdev->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/sht15.c b/drivers/hwmon/sht15.c
index 303c02694c3c..ebe38b680ee3 100644
--- a/drivers/hwmon/sht15.c
+++ b/drivers/hwmon/sht15.c
@@ -30,6 +30,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
+#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/err.h>
@@ -622,7 +623,12 @@ static int __devexit sht15_remove(struct platform_device *pdev)
}
-static struct platform_driver sht_drivers[] = {
+/*
+ * sht_drivers simultaneously refers to __devinit and __devexit function
+ * which causes spurious section mismatch warning. So use __refdata to
+ * get rid from this.
+ */
+static struct platform_driver __refdata sht_drivers[] = {
{
.driver = {
.name = "sht10",
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..3814a2add31e 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.
@@ -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-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/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/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 28d09a5d8450..017c09540c2f 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -273,14 +273,8 @@ static const struct ide_proc_devset ide_generic_settings[] = {
static void proc_ide_settings_warn(void)
{
- static int warned;
-
- if (warned)
- return;
-
- printk(KERN_WARNING "Warning: /proc/ide/hd?/settings interface is "
+ printk_once(KERN_WARNING "Warning: /proc/ide/hd?/settings interface is "
"obsolete, and will be removed soon!\n");
- warned = 1;
}
static int ide_settings_proc_show(struct seq_file *m, void *v)
diff --git a/drivers/ide/sis5513.c b/drivers/ide/sis5513.c
index afca22beaadf..3b88eba04c9c 100644
--- a/drivers/ide/sis5513.c
+++ b/drivers/ide/sis5513.c
@@ -2,7 +2,7 @@
* Copyright (C) 1999-2000 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2002 Lionel Bouton <Lionel.Bouton@inet6.fr>, Maintainer
* Copyright (C) 2003 Vojtech Pavlik <vojtech@suse.cz>
- * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ * Copyright (C) 2007-2009 Bartlomiej Zolnierkiewicz
*
* May be copied or modified under the terms of the GNU General Public License
*
@@ -281,11 +281,13 @@ static void config_drive_art_rwp(ide_drive_t *drive)
pci_read_config_byte(dev, 0x4b, &reg4bh);
+ rw_prefetch = reg4bh & ~(0x11 << drive->dn);
+
if (drive->media == ide_disk)
- rw_prefetch = 0x11 << drive->dn;
+ rw_prefetch |= 0x11 << drive->dn;
- if ((reg4bh & (0x11 << drive->dn)) != rw_prefetch)
- pci_write_config_byte(dev, 0x4b, reg4bh|rw_prefetch);
+ if (reg4bh != rw_prefetch)
+ pci_write_config_byte(dev, 0x4b, rw_prefetch);
}
static void sis_set_pio_mode(ide_drive_t *drive, const u8 pio)
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 0bc3d78ce7b1..8aa56ac07e29 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -29,6 +29,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/fs.h>
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index d287ba79821d..949064a05675 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -30,6 +30,7 @@
*/
#include <linux/kernel.h>
#include <linux/list.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 5be1bd4fc7ed..bd07803e9183 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -393,7 +393,7 @@ static int addr_resolve_local(struct sockaddr *src_in,
for_each_netdev(&init_net, dev)
if (ipv6_chk_addr(&init_net,
- &((struct sockaddr_in6 *) addr)->sin6_addr,
+ &((struct sockaddr_in6 *) dst_in)->sin6_addr,
dev, 1))
break;
diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c
index 55d093a36ae4..0f89909abce9 100644
--- a/drivers/infiniband/core/iwcm.c
+++ b/drivers/infiniband/core/iwcm.c
@@ -40,6 +40,7 @@
#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/rbtree.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
#include <linux/completion.h>
@@ -362,7 +363,9 @@ static void destroy_cm_id(struct iw_cm_id *cm_id)
* In either case, must tell the provider to reject.
*/
cm_id_priv->state = IW_CM_STATE_DESTROYING;
+ spin_unlock_irqrestore(&cm_id_priv->lock, flags);
cm_id->device->iwcm->reject(cm_id, NULL, 0);
+ spin_lock_irqsave(&cm_id_priv->lock, flags);
break;
case IW_CM_STATE_CONN_SENT:
case IW_CM_STATE_DESTROYING:
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 4346a24568fb..bb96d3c4b0f4 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -34,6 +34,7 @@
#include <linux/file.h>
#include <linux/mutex.h>
#include <linux/poll.h>
+#include <linux/sched.h>
#include <linux/idr.h>
#include <linux/in.h>
#include <linux/in6.h>
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index 6895523779d0..ed7175549ebd 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -37,6 +37,7 @@
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/list.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
@@ -1199,11 +1200,14 @@ static int iwch_query_port(struct ib_device *ibdev,
props->state = IB_PORT_DOWN;
else {
inetdev = in_dev_get(netdev);
- if (inetdev->ifa_list)
- props->state = IB_PORT_ACTIVE;
- else
+ if (inetdev) {
+ if (inetdev->ifa_list)
+ props->state = IB_PORT_ACTIVE;
+ else
+ props->state = IB_PORT_INIT;
+ in_dev_put(inetdev);
+ } else
props->state = IB_PORT_INIT;
- in_dev_put(inetdev);
}
props->port_cap_flags =
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 6e8653471941..1cecf98829ac 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -29,6 +29,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
+#include <linux/sched.h>
#include "iwch_provider.h"
#include "iwch.h"
#include "iwch_cm.h"
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 04e88b600558..013d1380e77c 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -31,6 +31,7 @@
* SOFTWARE.
*/
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/idr.h>
#include <linux/pci.h>
diff --git a/drivers/infiniband/hw/ipath/ipath_iba7220.c b/drivers/infiniband/hw/ipath/ipath_iba7220.c
index b2a9d4c155d1..a805402dd4ae 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba7220.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba7220.c
@@ -37,6 +37,7 @@
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <rdma/ib_verbs.h>
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index 6c21b4b5ec71..c0a03ac03ee7 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -33,6 +33,7 @@
#include <linux/pci.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#include "ipath_kernel.h"
#include "ipath_verbs.h"
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 3a5a89b609c4..cb2d3ef2ae12 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -32,6 +32,7 @@
*/
#include <linux/err.h>
+#include <linux/sched.h>
#include <linux/vmalloc.h>
#include "ipath_verbs.h"
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index 2296832f94da..1f95bbaf7602 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -31,6 +31,7 @@
* SOFTWARE.
*/
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include "ipath_verbs.h"
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index 6076cb61bf6a..7420715256a9 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -31,6 +31,7 @@
* SOFTWARE.
*/
+#include <linux/sched.h>
#include <rdma/ib_smi.h>
#include "ipath_verbs.h"
diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c
index 855911e7396d..82878e348627 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_pages.c
+++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c
@@ -33,6 +33,7 @@
#include <linux/mm.h>
#include <linux/device.h>
+#include <linux/sched.h>
#include "ipath_kernel.h"
diff --git a/drivers/infiniband/hw/ipath/ipath_user_sdma.c b/drivers/infiniband/hw/ipath/ipath_user_sdma.c
index 7bff4b9baa0a..be78f6643c06 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_sdma.c
+++ b/drivers/infiniband/hw/ipath/ipath_user_sdma.c
@@ -33,6 +33,7 @@
#include <linux/types.h>
#include <linux/device.h>
#include <linux/dmapool.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/highmem.h>
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
index d73e32232879..6923e1d986da 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c
@@ -32,6 +32,7 @@
*/
#include <linux/rculist.h>
+#include <linux/sched.h>
#include "ipath_verbs.h"
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/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 0ba6ec876296..add9188663ff 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -426,7 +426,7 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep,
* because we preallocate so many resources
*/
cls_session = iscsi_session_setup(&iscsi_iser_transport, shost,
- ISCSI_DEF_XMIT_CMDS_MAX,
+ ISCSI_DEF_XMIT_CMDS_MAX, 0,
sizeof(struct iscsi_iser_task),
initial_cmdsn, 0);
if (!cls_session)
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/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 2388cf578a62..79e3edcced1a 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -143,6 +143,7 @@ static const struct xpad_device {
{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+ { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
@@ -209,6 +210,7 @@ static struct usb_device_id xpad_table [] = {
XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
+ XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */
XPAD_XBOX360_VENDOR(0x1bad), /* Rock Band Drums */
{ }
};
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..022f3cb85d4e 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -574,11 +574,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 +781,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;
@@ -1087,6 +1122,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 +1303,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);
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/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index e9d639ec283d..5f72440b50c8 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -24,6 +24,7 @@
#include <linux/interrupt.h>
#include <linux/hil.h>
#include <linux/io.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <asm/irq.h>
#ifdef CONFIG_HP300
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/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index 472b56639cdb..a99a04b03ee4 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -27,6 +27,7 @@
*/
#include <linux/delay.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/interrupt.h>
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index c806fbf1e174..3b9f588fc747 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -106,8 +106,8 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev)
struct input_dev *input;
int err;
- if (!pdata || !pdata->steps) {
- dev_err(&pdev->dev, "invalid platform data\n");
+ if (!pdata) {
+ dev_err(&pdev->dev, "missing platform data\n");
return -ENOENT;
}
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index c4f42311fdec..b064419b90a2 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -230,7 +230,7 @@ out_err:
return err;
}
-static int bbc_remove(struct of_device *op)
+static int __devexit bbc_remove(struct of_device *op)
{
struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
struct input_dev *input_dev = state->input_dev;
@@ -308,7 +308,7 @@ out_err:
return err;
}
-static int grover_remove(struct of_device *op)
+static int __devexit grover_remove(struct of_device *op)
{
struct sparcspkr_state *state = dev_get_drvdata(&op->dev);
struct grover_beep_info *info = &state->u.grover;
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 11fd038a078f..a932179c4c9e 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -936,6 +936,15 @@ static struct dmi_system_id dmi_ids[] __initdata = {
},
{
.callback = dmi_matched,
+ .ident = "Medion MD 42200",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Medion"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "WIM 2030"),
+ },
+ .driver_data = keymap_fs_amilo_pro_v2000
+ },
+ {
+ .callback = dmi_matched,
.ident = "Medion MD 96500",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MEDIONPC"),
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 c4b3fbd1a80f..7e319d65ec57 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -4,7 +4,7 @@
config SERIO
tristate "Serial I/O support" if EMBEDDED || !X86
default y
- ---help---
+ help
Say Yes here if you have any input device that uses serial I/O to
communicate with the system. This includes the
* standard AT keyboard and PS/2 mouse *
@@ -22,7 +22,7 @@ config SERIO_I8042
tristate "i8042 PC Keyboard controller" if EMBEDDED || !X86
default y
depends on !PARISC && (!ARM || ARCH_SHARK || FOOTBRIDGE_HOST) && !M68K && !BLACKFIN
- ---help---
+ help
i8042 is the chip over which the standard AT keyboard and PS/2
mouse are connected to the computer. If you use these devices,
you'll need to say Y here.
@@ -35,7 +35,7 @@ config SERIO_I8042
config SERIO_SERPORT
tristate "Serial port line discipline"
default y
- ---help---
+ help
Say Y here if you plan to use an input device (mouse, joystick,
tablet, 6dof) that communicates over the RS232 serial (COM) port.
@@ -49,7 +49,7 @@ config SERIO_SERPORT
config SERIO_CT82C710
tristate "ct82c710 Aux port controller"
depends on X86
- ---help---
+ help
Say Y here if you have a Texas Instruments TravelMate notebook
equipped with the ct82c710 chip and want to use a mouse connected
to the "QuickPort".
@@ -66,7 +66,7 @@ config SERIO_Q40KBD
config SERIO_PARKBD
tristate "Parallel port keyboard adapter"
depends on PARPORT
- ---help---
+ help
Say Y here if you built a simple parallel port adapter to attach
an additional AT keyboard, XT keyboard or PS/2 mouse.
@@ -124,7 +124,7 @@ config HP_SDC
tristate "HP System Device Controller i8042 Support"
depends on (GSC || HP300) && SERIO
default y
- ---help---
+ help
This option enables support for the "System Device
Controller", an i8042 carrying microcode to manage a
few miscellaneous devices on some Hewlett Packard systems.
@@ -168,6 +168,7 @@ config SERIO_MACEPS2
config SERIO_LIBPS2
tristate "PS/2 driver library" if EMBEDDED
+ depends on SERIO_I8042 || SERIO_I8042=n
help
Say Y here if you are using a driver for device connected
to a PS/2 port, such as PS/2 mouse or standard AT keyboard.
@@ -200,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..77ff205c8577 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -661,7 +661,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/serio/i8042.c b/drivers/input/serio/i8042.c
index bc56e52b945f..a31578170ccc 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -609,6 +609,8 @@ static irqreturn_t __init i8042_aux_test_irq(int irq, void *dev_id)
str = i8042_read_status();
if (str & I8042_STR_OBF) {
data = i8042_read_data();
+ dbg("%02x <- i8042 (aux_test_irq, %s)",
+ data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
if (i8042_irq_being_tested &&
data == 0xa5 && (str & I8042_STR_AUXDATA))
complete(&i8042_aux_irq_delivered);
@@ -750,6 +752,7 @@ static int __init i8042_check_aux(void)
* AUX IRQ was never delivered so we need to flush the controller to
* get rid of the byte we put there; otherwise keyboard may not work.
*/
+ dbg(" -- i8042 (aux irq test timeout)");
i8042_flush();
retval = -1;
}
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 769ba65a585a..f3876acc3e83 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index b03009bb7468..27fdaaffbb40 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -9,6 +9,7 @@
* the Free Software Foundation.
*/
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/poll.h>
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index b9694b6445d0..6d345112bcb7 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -15,6 +15,7 @@
#include <asm/uaccess.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index f06332c9e21b..c21e6d3a8844 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -645,7 +645,7 @@ static int __devinit ad7879_probe(struct spi_device *spi)
kfree(ts);
}
- return 0;
+ return error;
}
static int __devexit ad7879_remove(struct spi_device *spi)
@@ -732,7 +732,7 @@ static int __devinit ad7879_probe(struct i2c_client *client,
kfree(ts);
}
- return 0;
+ return error;
}
static int __devexit ad7879_remove(struct i2c_client *client)
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 2d8352419c0d..65bf91e16a42 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -603,7 +603,7 @@ static void capi_recv_message(struct capi20_appl *ap, struct sk_buff *skb)
if (CAPIMSG_CMD(skb->data) == CAPI_CONNECT_B3_CONF) {
u16 info = CAPIMSG_U16(skb->data, 12); // Info field
- if (info == 0) {
+ if ((info & 0xff00) == 0) {
mutex_lock(&cdev->ncci_list_mtx);
capincci_alloc(cdev, CAPIMSG_NCCI(skb->data));
mutex_unlock(&cdev->ncci_list_mtx);
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index 650120261abf..3e6d17f42a98 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -40,7 +40,7 @@ static int debugmode = 0;
MODULE_DESCRIPTION("CAPI4Linux: Interface to ISDN4Linux");
MODULE_AUTHOR("Carsten Paeth");
MODULE_LICENSE("GPL");
-module_param(debugmode, uint, 0);
+module_param(debugmode, uint, S_IRUGO|S_IWUSR);
/* -------- type definitions ----------------------------------------- */
@@ -671,8 +671,8 @@ static void n0(capidrv_contr * card, capidrv_ncci * ncci)
NULL, /* Useruserdata */ /* $$$$ */
NULL /* Facilitydataarray */
);
- send_message(card, &cmsg);
plci_change_state(card, ncci->plcip, EV_PLCI_DISCONNECT_REQ);
+ send_message(card, &cmsg);
cmd.command = ISDN_STAT_BHUP;
cmd.driver = card->myid;
@@ -924,8 +924,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
*/
capi_cmsg_answer(cmsg);
cmsg->Reject = 1; /* ignore */
- send_message(card, cmsg);
plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
+ send_message(card, cmsg);
printk(KERN_INFO "capidrv-%d: incoming call %s,%d,%d,%s ignored\n",
card->contrnr,
cmd.parm.setup.phone,
@@ -974,8 +974,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
case 2: /* Call will be rejected. */
capi_cmsg_answer(cmsg);
cmsg->Reject = 2; /* reject call, normal call clearing */
- send_message(card, cmsg);
plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
+ send_message(card, cmsg);
break;
default:
@@ -983,8 +983,8 @@ static void handle_incoming_call(capidrv_contr * card, _cmsg * cmsg)
capi_cmsg_answer(cmsg);
cmsg->Reject = 8; /* reject call,
destination out of order */
- send_message(card, cmsg);
plci_change_state(card, plcip, EV_PLCI_CONNECT_REJECT);
+ send_message(card, cmsg);
break;
}
return;
@@ -1020,8 +1020,8 @@ static void handle_plci(_cmsg * cmsg)
card->bchans[plcip->chan].disconnecting = 1;
plci_change_state(card, plcip, EV_PLCI_DISCONNECT_IND);
capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
plci_change_state(card, plcip, EV_PLCI_DISCONNECT_RESP);
+ send_message(card, cmsg);
break;
case CAPI_DISCONNECT_CONF: /* plci */
@@ -1078,8 +1078,8 @@ static void handle_plci(_cmsg * cmsg)
if (card->bchans[plcip->chan].incoming) {
capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
+ send_message(card, cmsg);
} else {
capidrv_ncci *nccip;
capi_cmsg_answer(cmsg);
@@ -1098,13 +1098,14 @@ static void handle_plci(_cmsg * cmsg)
NULL /* NCPI */
);
nccip->msgid = cmsg->Messagenumber;
+ plci_change_state(card, plcip,
+ EV_PLCI_CONNECT_ACTIVE_IND);
+ ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
send_message(card, cmsg);
cmd.command = ISDN_STAT_DCONN;
cmd.driver = card->myid;
cmd.arg = plcip->chan;
card->interface.statcallb(&cmd);
- plci_change_state(card, plcip, EV_PLCI_CONNECT_ACTIVE_IND);
- ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_REQ);
}
break;
@@ -1193,8 +1194,8 @@ static void handle_ncci(_cmsg * cmsg)
goto notfound;
capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_ACTIVE_IND);
+ send_message(card, cmsg);
cmd.command = ISDN_STAT_BCONN;
cmd.driver = card->myid;
@@ -1222,8 +1223,8 @@ static void handle_ncci(_cmsg * cmsg)
0, /* Reject */
NULL /* NCPI */
);
- send_message(card, cmsg);
ncci_change_state(card, nccip, EV_NCCI_CONNECT_B3_RESP);
+ send_message(card, cmsg);
break;
}
printk(KERN_ERR "capidrv-%d: no mem for ncci, sorry\n", card->contrnr);
@@ -1299,8 +1300,8 @@ static void handle_ncci(_cmsg * cmsg)
card->bchans[nccip->chan].disconnecting = 1;
ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_IND);
capi_cmsg_answer(cmsg);
- send_message(card, cmsg);
ncci_change_state(card, nccip, EV_NCCI_DISCONNECT_B3_RESP);
+ send_message(card, cmsg);
break;
case CAPI_DISCONNECT_B3_CONF: /* ncci */
@@ -2014,8 +2015,8 @@ static void send_listen(capidrv_contr *card)
card->cipmask,
card->cipmask2,
NULL, NULL);
- send_message(card, &cmdcmsg);
listen_change_state(card, EV_LISTEN_REQ);
+ send_message(card, &cmdcmsg);
}
static void listentimerfunc(unsigned long x)
diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c
index 57d26360f64e..dc506ab99cac 100644
--- a/drivers/isdn/capi/kcapi.c
+++ b/drivers/isdn/capi/kcapi.c
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
+#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/skbuff.h>
#include <linux/workqueue.h>
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 234cc5d53312..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;
+ }
}
}
@@ -334,7 +319,14 @@ static inline int iraw_loop(unsigned char c, unsigned char *src, int numbytes,
return startbytes - numbytes;
}
-/* process a block of data received from the device
+/**
+ * gigaset_m10x_input() - process a block of data received from the device
+ * @inbuf: received data and device descriptor structure.
+ *
+ * Called by hardware module {ser,usb}_gigaset with a block of received
+ * bytes. Separates the bytes received over the serial data channel into
+ * user data and command replies (locked/unlocked) according to the
+ * current state of the interface.
*/
void gigaset_m10x_input(struct inbuf_t *inbuf)
{
@@ -376,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);
@@ -433,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;
@@ -464,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;
@@ -508,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;
@@ -524,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;
@@ -543,26 +540,29 @@ static struct sk_buff *iraw_encode(struct sk_buff *skb, int head, int tail)
return iraw_skb;
}
-/* gigaset_send_skb
- * called by common.c to queue an skb for sending
- * and start transmission if necessary
- * parameters:
- * B Channel control structure
- * skb
+/**
+ * gigaset_m10x_send_skb() - queue an skb for sending
+ * @bcs: B channel descriptor structure.
+ * @skb: data to send.
+ *
+ * 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, 0 if out of buffer space)
- * or error code (< 0, eg. -EINVAL)
+ * number of bytes accepted for sending (skb->len) if ok,
+ * error code < 0 (eg. -ENOMEM) on error
*/
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 781c4041f7b0..388e63a8ae94 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -134,6 +134,7 @@ struct bas_cardstate {
#define BS_ATRDPEND 0x040 /* urb_cmd_in in use */
#define BS_ATWRPEND 0x080 /* urb_cmd_out in use */
#define BS_SUSPEND 0x100 /* USB port suspended */
+#define BS_RESETTING 0x200 /* waiting for HD_RESET_INTERRUPT_PIPE_ACK */
static struct gigaset_driver *driver = NULL;
@@ -319,6 +320,21 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
return -EINVAL;
}
+/* set/clear bits in base connection state, return previous state
+ */
+static inline int update_basstate(struct bas_cardstate *ucs,
+ int set, int clear)
+{
+ unsigned long flags;
+ int state;
+
+ spin_lock_irqsave(&ucs->lock, flags);
+ state = ucs->basstate;
+ ucs->basstate = (state & ~clear) | set;
+ spin_unlock_irqrestore(&ucs->lock, flags);
+ return state;
+}
+
/* error_hangup
* hang up any existing connection because of an unrecoverable error
* This function may be called from any context and takes care of scheduling
@@ -350,12 +366,9 @@ static inline void error_hangup(struct bc_state *bcs)
*/
static inline void error_reset(struct cardstate *cs)
{
- /* close AT command channel to recover (ignore errors) */
- req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT);
-
- //FIXME try to recover without bothering the user
- dev_err(cs->dev,
- "unrecoverable error - please disconnect Gigaset base to reset\n");
+ /* reset interrupt pipe to recover (ignore errors) */
+ update_basstate(cs->hw.bas, BS_RESETTING, 0);
+ req_submit(cs->bcs, HD_RESET_INTERRUPT_PIPE, 0, BAS_TIMEOUT);
}
/* check_pending
@@ -398,8 +411,13 @@ static void check_pending(struct bas_cardstate *ucs)
case HD_DEVICE_INIT_ACK: /* no reply expected */
ucs->pending = 0;
break;
- /* HD_READ_ATMESSAGE, HD_WRITE_ATMESSAGE, HD_RESET_INTERRUPTPIPE
- * are handled separately and should never end up here
+ case HD_RESET_INTERRUPT_PIPE:
+ if (!(ucs->basstate & BS_RESETTING))
+ ucs->pending = 0;
+ break;
+ /*
+ * HD_READ_ATMESSAGE and HD_WRITE_ATMESSAGE are handled separately
+ * and should never end up here
*/
default:
dev_warn(&ucs->interface->dev,
@@ -449,21 +467,6 @@ static void cmd_in_timeout(unsigned long data)
error_reset(cs);
}
-/* set/clear bits in base connection state, return previous state
- */
-inline static int update_basstate(struct bas_cardstate *ucs,
- int set, int clear)
-{
- unsigned long flags;
- int state;
-
- spin_lock_irqsave(&ucs->lock, flags);
- state = ucs->basstate;
- ucs->basstate = (state & ~clear) | set;
- spin_unlock_irqrestore(&ucs->lock, flags);
- return state;
-}
-
/* read_ctrl_callback
* USB completion handler for control pipe input
* called by the USB subsystem in interrupt context
@@ -762,7 +765,8 @@ static void read_int_callback(struct urb *urb)
break;
case HD_RESET_INTERRUPT_PIPE_ACK:
- gig_dbg(DEBUG_USBREQ, "HD_RESET_INTERRUPT_PIPE_ACK");
+ update_basstate(ucs, 0, BS_RESETTING);
+ dev_notice(cs->dev, "interrupt pipe reset\n");
break;
case HD_SUSPEND_END:
@@ -907,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 */
@@ -1060,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",
@@ -1331,28 +1335,24 @@ static void read_iso_tasklet(unsigned long data)
rcvbuf = urb->transfer_buffer;
totleft = urb->actual_length;
for (frame = 0; totleft > 0 && frame < BAS_NUMFRAMES; frame++) {
- if (unlikely(urb->iso_frame_desc[frame].status)) {
+ numbytes = urb->iso_frame_desc[frame].actual_length;
+ if (unlikely(urb->iso_frame_desc[frame].status))
dev_warn(cs->dev,
- "isochronous read: frame %d: %s\n",
- frame,
+ "isochronous read: frame %d[%d]: %s\n",
+ frame, numbytes,
get_usb_statmsg(
urb->iso_frame_desc[frame].status));
- break;
- }
- numbytes = urb->iso_frame_desc[frame].actual_length;
- if (unlikely(numbytes > BAS_MAXFRAME)) {
+ if (unlikely(numbytes > BAS_MAXFRAME))
dev_warn(cs->dev,
"isochronous read: frame %d: "
"numbytes (%d) > BAS_MAXFRAME\n",
frame, numbytes);
- break;
- }
if (unlikely(numbytes > totleft)) {
dev_warn(cs->dev,
"isochronous read: frame %d: "
"numbytes (%d) > totleft (%d)\n",
frame, numbytes, totleft);
- break;
+ numbytes = totleft;
}
offset = urb->iso_frame_desc[frame].offset;
if (unlikely(offset + numbytes > BAS_INBUFSIZE)) {
@@ -1361,7 +1361,7 @@ static void read_iso_tasklet(unsigned long data)
"offset (%d) + numbytes (%d) "
"> BAS_INBUFSIZE\n",
frame, offset, numbytes);
- break;
+ numbytes = BAS_INBUFSIZE - offset;
}
gigaset_isoc_receive(rcvbuf + offset, numbytes, bcs);
totleft -= numbytes;
@@ -1433,6 +1433,7 @@ static void req_timeout(unsigned long data)
case HD_CLOSE_ATCHANNEL:
dev_err(bcs->cs->dev, "timeout closing AT channel\n");
+ error_reset(bcs->cs);
break;
case HD_CLOSE_B2CHANNEL:
@@ -1442,6 +1443,13 @@ static void req_timeout(unsigned long data)
error_reset(bcs->cs);
break;
+ case HD_RESET_INTERRUPT_PIPE:
+ /* error recovery escalation */
+ dev_err(bcs->cs->dev,
+ "reset interrupt pipe timeout, attempting USB reset\n");
+ usb_queue_reset_device(bcs->cs->hw.bas->interface);
+ break;
+
default:
dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n",
pending);
@@ -1934,6 +1942,15 @@ static int gigaset_write_cmd(struct cardstate *cs,
goto notqueued;
}
+ /* translate "+++" escape sequence sent as a single separate command
+ * into "close AT channel" command for error recovery
+ * The next command will reopen the AT channel automatically.
+ */
+ if (len == 3 && !memcmp(buf, "+++", 3)) {
+ rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, BAS_TIMEOUT);
+ goto notqueued;
+ }
+
if (len > IF_WRITEBUF)
len = IF_WRITEBUF;
if (!(cb = kmalloc(sizeof(struct cmdbuf_t) + len, GFP_ATOMIC))) {
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 e4141bf8b2f3..1d2ae2e05e0b 100644
--- a/drivers/isdn/gigaset/common.c
+++ b/drivers/isdn/gigaset/common.c
@@ -22,6 +22,12 @@
#define DRIVER_AUTHOR "Hansjoerg Lipp <hjlipp@web.de>, Tilman Schmidt <tilman@imap.cc>, Stefan Eilers"
#define DRIVER_DESC "Driver for Gigaset 307x"
+#ifdef CONFIG_GIGASET_DEBUG
+#define DRIVER_DESC_DEBUG " (debug build)"
+#else
+#define DRIVER_DESC_DEBUG ""
+#endif
+
/* Module parameters */
int gigaset_debuglevel = DEBUG_DEFAULT;
EXPORT_SYMBOL_GPL(gigaset_debuglevel);
@@ -32,6 +38,17 @@ MODULE_PARM_DESC(debug, "debug level");
#define VALID_MINOR 0x01
#define VALID_ID 0x02
+/**
+ * gigaset_dbg_buffer() - dump data in ASCII and hex for debugging
+ * @level: debugging level.
+ * @msg: message prefix.
+ * @len: number of bytes to dump.
+ * @buf: data to dump.
+ *
+ * If the current debugging level includes one of the bits set in @level,
+ * @len bytes starting at @buf are logged to dmesg at KERN_DEBUG prio,
+ * prefixed by the text @msg.
+ */
void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg,
size_t len, const unsigned char *buf)
{
@@ -190,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;
@@ -274,6 +317,20 @@ static void clear_events(struct cardstate *cs)
spin_unlock_irqrestore(&cs->ev_lock, flags);
}
+/**
+ * gigaset_add_event() - add event to device event queue
+ * @cs: device descriptor structure.
+ * @at_state: connection state structure.
+ * @type: event type.
+ * @ptr: pointer parameter for event.
+ * @parameter: integer parameter for event.
+ * @arg: pointer parameter for event.
+ *
+ * Allocate an event queue entry from the device's event queue, and set it up
+ * with the parameters given.
+ *
+ * Return value: added event
+ */
struct event_t *gigaset_add_event(struct cardstate *cs,
struct at_state_t *at_state, int type,
void *ptr, int parameter, void *arg)
@@ -398,6 +455,15 @@ static void make_invalid(struct cardstate *cs, unsigned mask)
spin_unlock_irqrestore(&drv->lock, flags);
}
+/**
+ * gigaset_freecs() - free all associated ressources of a device
+ * @cs: device descriptor structure.
+ *
+ * Stops all tasklets and timers, unregisters the device from all
+ * subsystems it was registered to, deallocates the device structure
+ * @cs and all structures referenced from it.
+ * Operations on the device should be stopped before calling this.
+ */
void gigaset_freecs(struct cardstate *cs)
{
int i;
@@ -423,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);
@@ -437,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);
@@ -506,7 +572,12 @@ static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs,
inbuf->inputstate = inputstate;
}
-/* append received bytes to inbuf */
+/**
+ * gigaset_fill_inbuf() - append received data to input buffer
+ * @inbuf: buffer structure.
+ * @src: received data.
+ * @numbytes: number of bytes received.
+ */
int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src,
unsigned numbytes)
{
@@ -575,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;
@@ -606,20 +680,22 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs,
return NULL;
}
-/* gigaset_initcs
+/**
+ * gigaset_initcs() - initialize device structure
+ * @drv: hardware driver the device belongs to
+ * @channels: number of B channels supported by device
+ * @onechannel: !=0 if B channel data and AT commands share one
+ * communication channel (M10x),
+ * ==0 if B channels have separate communication channels (base)
+ * @ignoreframes: number of frames to ignore after setting up B channel
+ * @cidmode: !=0: start in CallID mode
+ * @modulename: name of driver module for LL registration
+ *
* Allocate and initialize cardstate structure for Gigaset driver
* Calls hardware dependent gigaset_initcshw() function
* Calls B channel initialization function gigaset_initbcs() for each B channel
- * parameters:
- * drv hardware driver the device belongs to
- * channels number of B channels supported by device
- * onechannel !=0: B channel data and AT commands share one
- * communication channel
- * ==0: B channels have separate communication channels
- * ignoreframes number of frames to ignore after setting up B channel
- * cidmode !=0: start in CallID mode
- * modulename name of driver module (used for I4L registration)
- * return value:
+ *
+ * Return value:
* pointer to cardstate structure
*/
struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels,
@@ -679,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");
@@ -711,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;
}
@@ -730,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);
@@ -837,6 +914,17 @@ static void cleanup_cs(struct cardstate *cs)
}
+/**
+ * gigaset_start() - start device operations
+ * @cs: device descriptor structure.
+ *
+ * Prepares the device for use by setting up communication parameters,
+ * scheduling an EV_START event to initiate device initialization, and
+ * waiting for completion of the initialization.
+ *
+ * Return value:
+ * 1 - success, 0 - error
+ */
int gigaset_start(struct cardstate *cs)
{
unsigned long flags;
@@ -879,9 +967,15 @@ error:
}
EXPORT_SYMBOL_GPL(gigaset_start);
-/* gigaset_shutdown
- * check if a device is associated to the cardstate structure and stop it
- * return value: 0 if ok, -1 if no device was associated
+/**
+ * gigaset_shutdown() - shut down device operations
+ * @cs: device descriptor structure.
+ *
+ * Deactivates the device by scheduling an EV_SHUTDOWN event and
+ * waiting for completion of the shutdown.
+ *
+ * Return value:
+ * 0 - success, -1 - error (no device associated)
*/
int gigaset_shutdown(struct cardstate *cs)
{
@@ -912,6 +1006,13 @@ exit:
}
EXPORT_SYMBOL_GPL(gigaset_shutdown);
+/**
+ * gigaset_stop() - stop device operations
+ * @cs: device descriptor structure.
+ *
+ * Stops operations on the device by scheduling an EV_STOP event and
+ * waiting for completion of the shutdown.
+ */
void gigaset_stop(struct cardstate *cs)
{
mutex_lock(&cs->mutex);
@@ -1020,6 +1121,14 @@ struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty)
return gigaset_get_cs_by_minor(tty->index + tty->driver->minor_start);
}
+/**
+ * gigaset_freedriver() - free all associated ressources of a driver
+ * @drv: driver descriptor structure.
+ *
+ * Unregisters the driver from the system and deallocates the driver
+ * structure @drv and all structures referenced from it.
+ * All devices should be shut down before calling this.
+ */
void gigaset_freedriver(struct gigaset_driver *drv)
{
unsigned long flags;
@@ -1035,14 +1144,16 @@ void gigaset_freedriver(struct gigaset_driver *drv)
}
EXPORT_SYMBOL_GPL(gigaset_freedriver);
-/* gigaset_initdriver
+/**
+ * gigaset_initdriver() - initialize driver structure
+ * @minor: First minor number
+ * @minors: Number of minors this driver can handle
+ * @procname: Name of the driver
+ * @devname: Name of the device files (prefix without minor number)
+ *
* Allocate and initialize gigaset_driver structure. Initialize interface.
- * parameters:
- * minor First minor number
- * minors Number of minors this driver can handle
- * procname Name of the driver
- * devname Name of the device files (prefix without minor number)
- * return value:
+ *
+ * Return value:
* Pointer to the gigaset_driver structure on success, NULL on failure.
*/
struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors,
@@ -1095,6 +1206,13 @@ error:
}
EXPORT_SYMBOL_GPL(gigaset_initdriver);
+/**
+ * gigaset_blockdriver() - block driver
+ * @drv: driver descriptor structure.
+ *
+ * Prevents the driver from attaching new devices, in preparation for
+ * deregistration.
+ */
void gigaset_blockdriver(struct gigaset_driver *drv)
{
drv->blocked = 1;
@@ -1110,7 +1228,7 @@ static int __init gigaset_init_module(void)
if (gigaset_debuglevel == 1)
gigaset_debuglevel = DEBUG_DEFAULT;
- pr_info(DRIVER_DESC "\n");
+ pr_info(DRIVER_DESC DRIVER_DESC_DEBUG "\n");
return 0;
}
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 2d91049571a4..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
@@ -207,7 +206,6 @@ struct reply_t gigaset_tab_nocid[] =
/* leave dle mode */
{RSP_INIT, 0, 0,SEQ_DLE0, 201, 5, {0}, "^SDLE=0\r"},
{RSP_OK, 201,201, -1, 202,-1},
- //{RSP_ZDLE, 202,202, 0, 202, 0, {ACT_ERROR}},//DELETE
{RSP_ZDLE, 202,202, 0, 0, 0, {ACT_DLE0}},
{RSP_NODEV, 200,249, -1, 0, 0, {ACT_FAKEDLE0}},
{RSP_ERROR, 200,249, -1, 0, 0, {ACT_FAILDLE0}},
@@ -265,6 +263,7 @@ struct reply_t gigaset_tab_nocid[] =
{EV_SHUTDOWN, -1, -1, -1, -1,-1, {ACT_SHUTDOWN}}, //FIXME
/* misc. */
+ {RSP_ERROR, -1, -1, -1, -1, -1, {ACT_ERROR} },
{RSP_EMPTY, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
{RSP_ZCFGT, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
{RSP_ZCFG, -1, -1, -1, -1,-1, {ACT_DEBUG}}, //FIXME
@@ -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 */
@@ -328,10 +329,9 @@ struct reply_t gigaset_tab_cid[] =
{RSP_INIT, -1, -1,SEQ_HUP, 401, 5, {0}, "+VLS=0\r"}, /* hang up */ //-1,-1?
{RSP_OK, 401,401, -1, 402, 5},
{RSP_ZVLS, 402,402, 0, 403, 5},
- {RSP_ZSAU, 403,403,ZSAU_DISCONNECT_REQ, -1,-1, {ACT_DEBUG}}, /* if not remote hup */
- //{RSP_ZSAU, 403,403,ZSAU_NULL, 401, 0, {ACT_ERROR}}, //DELETE//FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
- {RSP_ZSAU, 403,403,ZSAU_NULL, 0, 0, {ACT_DISCONNECT}}, //FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
- {RSP_NODEV, 401,403, -1, 0, 0, {ACT_FAKEHUP}}, //FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
+ {RSP_ZSAU, 403, 403, ZSAU_DISCONNECT_REQ, -1, -1, {ACT_DEBUG} },
+ {RSP_ZSAU, 403, 403, ZSAU_NULL, 0, 0, {ACT_DISCONNECT} },
+ {RSP_NODEV, 401, 403, -1, 0, 0, {ACT_FAKEHUP} },
{RSP_ERROR, 401,401, -1, 0, 0, {ACT_ABORTHUP}},
{EV_TIMEOUT, 401,403, -1, 0, 0, {ACT_ABORTHUP}},
@@ -366,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
@@ -474,8 +472,13 @@ static int cid_of_response(char *s)
//FIXME is ;<digit>+ at end of non-CID response really impossible?
}
-/* This function will be called via task queue from the callback handler.
- * We received a modem response and have to handle it..
+/**
+ * gigaset_handle_modem_response() - process received modem response
+ * @cs: device descriptor structure.
+ *
+ * Called by asyncdata/isocdata if a block of data received from the
+ * device must be processed as a modem command response. The data is
+ * already in the cs structure.
*/
void gigaset_handle_modem_response(struct cardstate *cs)
{
@@ -707,6 +710,11 @@ static void disconnect(struct at_state_t **at_state_p)
if (bcs) {
/* B channel assigned: invoke hardware specific handler */
cs->ops->close_bchannel(bcs);
+ /* notify LL */
+ if (bcs->chstate & (CHS_D_UP | CHS_NOTIFY_LL)) {
+ bcs->chstate &= ~(CHS_D_UP | CHS_NOTIFY_LL);
+ gigaset_isdn_hupD(bcs);
+ }
} else {
/* no B channel assigned: just deallocate */
spin_lock_irqsave(&cs->lock, flags);
@@ -863,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);
@@ -885,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;
@@ -904,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");
@@ -915,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;
@@ -924,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)
@@ -948,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
@@ -966,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. */
@@ -1267,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:
@@ -1275,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:
@@ -1429,11 +1453,12 @@ static void do_action(int action, struct cardstate *cs,
cs->gotfwver = -1;
dev_err(cs->dev, "could not read firmware version.\n");
break;
-#ifdef CONFIG_GIGASET_DEBUG
case ACT_ERROR:
- *p_genresp = 1;
- *p_resp_code = RSP_ERROR;
+ gig_dbg(DEBUG_ANY, "%s: ERROR response in ConState %d",
+ __func__, at_state->ConState);
+ cs->cur_at_seq = SEQ_NONE;
break;
+#ifdef CONFIG_GIGASET_DEBUG
case ACT_TEST:
{
static int count = 3; //2; //1;
@@ -1464,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 9b22f9cf2f33..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 =====================================================*/
@@ -51,6 +54,12 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
return -ENODEV;
}
bcs = &cs->bcs[channel];
+
+ /* can only handle linear sk_buffs */
+ if (skb_linearize(skb) < 0) {
+ dev_err(cs->dev, "%s: skb_linearize failed\n", __func__);
+ return -ENOMEM;
+ }
len = skb->len;
gig_dbg(DEBUG_LLDATA,
@@ -79,8 +88,17 @@ static int writebuf_from_LL(int driverID, int channel, int ack,
return cs->ops->send_skb(bcs, skb);
}
+/**
+ * gigaset_skb_sent() - acknowledge sending an 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 *skb)
{
+ isdn_if *iif = bcs->cs->iif;
unsigned len;
isdn_ctrl response;
@@ -100,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;
}
@@ -172,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;
}
@@ -310,155 +424,50 @@ 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);
}
+/**
+ * gigaset_isdn_icall() - signal incoming call
+ * @at_state: connection state structure.
+ *
+ * Called by main module 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;
+ isdn_if *iif = cs->iif;
isdn_ctrl response;
int retval;
@@ -508,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 */
@@ -537,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)
+{
+ gig_dbg(DEBUG_CMD, "sending DCONN");
+ gigaset_i4l_channel_cmd(bcs, ISDN_STAT_DCONN);
+}
+
+/**
+ * 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 = &cs->iif;
+ isdn_if *iif;
- gig_dbg(DEBUG_ANY, "Register driver capabilities to LL");
+ 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;
}
@@ -570,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/interface.c b/drivers/isdn/gigaset/interface.c
index f33ac27de643..6a8e1384e7bd 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -616,6 +616,15 @@ void gigaset_if_free(struct cardstate *cs)
tty_unregister_device(drv->tty, cs->minor_index);
}
+/**
+ * gigaset_if_receive() - pass a received block of data to the tty device
+ * @cs: device descriptor structure.
+ * @buffer: received data.
+ * @len: number of bytes received.
+ *
+ * Called by asyncdata/isocdata if a block of data received from the
+ * device must be sent to userspace through the ttyG* device.
+ */
void gigaset_if_receive(struct cardstate *cs,
unsigned char *buffer, size_t len)
{
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c
index bed38fcc432b..7dabfd35874c 100644
--- a/drivers/isdn/gigaset/isocdata.c
+++ b/drivers/isdn/gigaset/isocdata.c
@@ -429,7 +429,7 @@ static inline int hdlc_buildframe(struct isowbuf_t *iwb,
return -EAGAIN;
}
- dump_bytes(DEBUG_STREAM, "snd data", in, count);
+ dump_bytes(DEBUG_STREAM_DUMP, "snd data", in, count);
/* bitstuff and checksum input data */
fcs = PPP_INITFCS;
@@ -448,7 +448,6 @@ static inline int hdlc_buildframe(struct isowbuf_t *iwb,
/* put closing flag and repeat byte for flag idle */
isowbuf_putflag(iwb);
end = isowbuf_donewrite(iwb);
- dump_bytes(DEBUG_STREAM_DUMP, "isowbuf", iwb->data, end + 1);
return end;
}
@@ -482,6 +481,8 @@ static inline int trans_buildframe(struct isowbuf_t *iwb,
}
gig_dbg(DEBUG_STREAM, "put %d bytes", count);
+ dump_bytes(DEBUG_STREAM_DUMP, "snd data", in, count);
+
write = iwb->write;
do {
c = bitrev8(*in++);
@@ -499,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);
@@ -541,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");
}
@@ -556,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--;
@@ -567,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);
- dump_bytes(DEBUG_STREAM,
- "rcv data", procskb->data, procskb->len);
- bcs->hw.bas->goodbytes += procskb->len;
- gigaset_rcv_skb(procskb, bcs->cs, bcs);
+ 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, 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;
}
@@ -609,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;
}
@@ -647,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
@@ -840,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:
@@ -851,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;
@@ -861,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;
@@ -878,14 +880,16 @@ static inline void trans_receive(unsigned char *src, unsigned count,
dobytes--;
}
if (dobytes == 0) {
- gigaset_rcv_skb(skb, bcs->cs, bcs);
- bcs->skb = skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN);
+ dump_bytes(DEBUG_STREAM_DUMP,
+ "rcv data", skb->data, skb->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;
}
}
@@ -894,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 */
@@ -973,16 +977,19 @@ void gigaset_isoc_input(struct inbuf_t *inbuf)
/* == data output ========================================================== */
-/* gigaset_send_skb
- * called by common.c to queue an skb for sending
- * and start transmission if necessary
- * parameters:
- * B Channel control structure
- * skb
- * return value:
- * number of bytes accepted for sending
- * (skb->len if ok, 0 if out of buffer space)
- * or error code (< 0, eg. -EINVAL)
+/**
+ * gigaset_isoc_send_skb() - queue an skb for sending
+ * @bcs: B channel descriptor structure.
+ * @skb: data to send.
+ *
+ * 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,
+ * error code < 0 (eg. -ENODEV) on error
*/
int gigaset_isoc_send_skb(struct bc_state *bcs, struct sk_buff *skb)
{
diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c
index d30ce5b978c2..85a8fd8dd0b7 100644
--- a/drivers/isdn/hisax/arcofi.c
+++ b/drivers/isdn/hisax/arcofi.c
@@ -10,6 +10,7 @@
*
*/
+#include <linux/sched.h>
#include "hisax.h"
#include "isdnl1.h"
#include "isac.h"
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index 5c46a7130e06..8d22f50760eb 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -11,6 +11,7 @@
*/
#include <linux/init.h>
+#include <linux/sched.h>
#include "hisax.h"
#include "hfc_2bds0.h"
#include "isdnl1.h"
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index d110a77940a4..10914731b304 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -20,6 +20,7 @@
#include "hfc_pci.h"
#include "isdnl1.h"
#include <linux/pci.h>
+#include <linux/sched.h>
#include <linux/interrupt.h>
static const char *hfcpci_revision = "$Revision: 1.48.2.4 $";
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 8f9f4912de32..90b35e1a4b7e 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/cred.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index 8991d2c8ee4a..8bcae28c4409 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
+#include <linux/sched.h>
#include <linux/smp_lock.h>
#include "hysdn_defs.h"
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/drv.c b/drivers/isdn/pcbit/drv.c
index 8c66bcb953a1..123c1d6c43b4 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
index e075e8d2fce0..30f0f45e3139 100644
--- a/drivers/isdn/pcbit/layer2.c
+++ b/drivers/isdn/pcbit/layer2.c
@@ -27,6 +27,7 @@
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index dd0acd06750b..5a0774880d56 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -8,6 +8,7 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#include "includes.h"
#include "hardware.h"
#include "card.h"
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-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/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c
index 18648180db02..daaf86631647 100644
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -16,6 +16,7 @@
#include <linux/uaccess.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/sched.h>
#include "lg.h"
/* Allow Guests to use a non-128 (ie. non-Linux) syscall trap. */
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index b40fb9b6c862..6f308a4757ee 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -405,7 +405,11 @@ static int __init via_pmu_start(void)
printk(KERN_ERR "via-pmu: can't map interrupt\n");
return -ENODEV;
}
- if (request_irq(irq, via_pmu_interrupt, 0, "VIA-PMU", (void *)0)) {
+ /* We set IRQF_TIMER because we don't want the interrupt to be disabled
+ * between the 2 passes of driver suspend, we control our own disabling
+ * for that one
+ */
+ if (request_irq(irq, via_pmu_interrupt, IRQF_TIMER, "VIA-PMU", (void *)0)) {
printk(KERN_ERR "via-pmu: can't request irq %d\n", irq);
return -ENODEV;
}
@@ -419,7 +423,7 @@ static int __init via_pmu_start(void)
gpio_irq = irq_of_parse_and_map(gpio_node, 0);
if (gpio_irq != NO_IRQ) {
- if (request_irq(gpio_irq, gpio1_interrupt, 0,
+ if (request_irq(gpio_irq, gpio1_interrupt, IRQF_TIMER,
"GPIO1 ADB", (void *)0))
printk(KERN_ERR "pmu: can't get irq %d"
" (GPIO1)\n", gpio_irq);
@@ -925,8 +929,7 @@ proc_write_options(struct file *file, const char __user *buffer,
#ifdef CONFIG_ADB
/* Send an ADB command */
-static int
-pmu_send_request(struct adb_request *req, int sync)
+static int pmu_send_request(struct adb_request *req, int sync)
{
int i, ret;
@@ -1005,16 +1008,11 @@ pmu_send_request(struct adb_request *req, int sync)
}
/* Enable/disable autopolling */
-static int
-pmu_adb_autopoll(int devs)
+static int __pmu_adb_autopoll(int devs)
{
struct adb_request req;
- if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
- return -ENXIO;
-
if (devs) {
- adb_dev_map = devs;
pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,
adb_dev_map >> 8, adb_dev_map);
pmu_adb_flags = 2;
@@ -1027,9 +1025,17 @@ pmu_adb_autopoll(int devs)
return 0;
}
+static int pmu_adb_autopoll(int devs)
+{
+ if ((vias == NULL) || (!pmu_fully_inited) || !pmu_has_adb)
+ return -ENXIO;
+
+ adb_dev_map = devs;
+ return __pmu_adb_autopoll(devs);
+}
+
/* Reset the ADB bus */
-static int
-pmu_adb_reset_bus(void)
+static int pmu_adb_reset_bus(void)
{
struct adb_request req;
int save_autopoll = adb_dev_map;
@@ -1038,13 +1044,13 @@ pmu_adb_reset_bus(void)
return -ENXIO;
/* anyone got a better idea?? */
- pmu_adb_autopoll(0);
+ __pmu_adb_autopoll(0);
- req.nbytes = 5;
+ req.nbytes = 4;
req.done = NULL;
req.data[0] = PMU_ADB_CMD;
- req.data[1] = 0;
- req.data[2] = ADB_BUSRESET;
+ req.data[1] = ADB_BUSRESET;
+ req.data[2] = 0;
req.data[3] = 0;
req.data[4] = 0;
req.reply_len = 0;
@@ -1056,7 +1062,7 @@ pmu_adb_reset_bus(void)
pmu_wait_complete(&req);
if (save_autopoll != 0)
- pmu_adb_autopoll(save_autopoll);
+ __pmu_adb_autopoll(save_autopoll);
return 0;
}
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index 556acff3952f..974a43934044 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,7 +211,7 @@ 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')
@@ -240,32 +228,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 +255,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 23e76fe0d359..724efc63904d 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;
};
/*
@@ -130,7 +131,7 @@ struct mapped_device {
/*
* A list of ios that arrived while we were suspended.
*/
- atomic_t pending;
+ atomic_t pending[2];
wait_queue_head_t wait;
struct work_struct work;
struct bio_list deferred;
@@ -453,13 +454,14 @@ static void start_io_acct(struct dm_io *io)
{
struct mapped_device *md = io->md;
int cpu;
+ int rw = bio_data_dir(io->bio);
io->start_time = jiffies;
cpu = part_stat_lock();
part_round_stats(cpu, &dm_disk(md)->part0);
part_stat_unlock();
- dm_disk(md)->part0.in_flight = atomic_inc_return(&md->pending);
+ dm_disk(md)->part0.in_flight[rw] = atomic_inc_return(&md->pending[rw]);
}
static void end_io_acct(struct dm_io *io)
@@ -479,8 +481,9 @@ static void end_io_acct(struct dm_io *io)
* After this is decremented the bio must not be touched if it is
* a barrier.
*/
- dm_disk(md)->part0.in_flight = pending =
- atomic_dec_return(&md->pending);
+ dm_disk(md)->part0.in_flight[rw] = pending =
+ atomic_dec_return(&md->pending[rw]);
+ pending += atomic_read(&md->pending[rw^0x1]);
/* nudge anyone waiting on suspend queue */
if (!pending)
@@ -576,8 +579,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) {
@@ -1224,6 +1231,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)))
@@ -1785,7 +1793,8 @@ static struct mapped_device *alloc_dev(int minor)
if (!md->disk)
goto bad_disk;
- atomic_set(&md->pending, 0);
+ atomic_set(&md->pending[0], 0);
+ atomic_set(&md->pending[1], 0);
init_waitqueue_head(&md->wait);
INIT_WORK(&md->work, dm_wq_work);
init_waitqueue_head(&md->eventq);
@@ -1819,6 +1828,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);
@@ -2088,7 +2098,8 @@ 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))
+ } else if (!atomic_read(&md->pending[0]) &&
+ !atomic_read(&md->pending[1]))
break;
if (interruptible == TASK_INTERRUPTIBLE &&
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 8c9ae0a3a272..0241a7c5c34a 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -63,6 +63,7 @@
#include <asm/uaccess.h>
#include <linux/crc32.h>
#include <linux/mutex.h>
+#include <linux/sched.h>
#include "dvb_demux.h"
#include "dvb_net.h"
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 4b1bc05a462c..01e1eefcf1eb 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -28,6 +28,7 @@
*/
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/sched.h>
#include <linux/init.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index f1ccf98c0a6f..8e93c6f25c83 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/mm.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 53cdd67cebe1..032ebae0134a 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -21,6 +21,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
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/mptlan.c b/drivers/message/fusion/mptlan.c
index bc2ec2182c00..34f3f36f819b 100644
--- a/drivers/message/fusion/mptlan.c
+++ b/drivers/message/fusion/mptlan.c
@@ -56,6 +56,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
+#include <linux/sched.h>
#define my_VERSION MPT_LINUX_VERSION_COMMON
#define MYNAM "mptlan"
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/Kconfig b/drivers/mfd/Kconfig
index fbe684b44dcc..bff73a2ac76c 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -160,6 +160,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 +181,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.
@@ -307,7 +317,7 @@ config EZX_PCAP
config MFD_88PM8607
bool "Support Marvell 88PM8607"
- depends on I2C
+ depends on I2C=y
select MFD_CORE
help
This supports for Marvell 88PM8607 Power Management IC. This includes
@@ -315,6 +325,16 @@ config MFD_88PM8607
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 e863c6403acc..297207cc4d69 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -10,14 +10,15 @@ 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,4 +51,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..401a9b6029e3
--- /dev/null
+++ b/drivers/mfd/adp5520.c
@@ -0,0 +1,378 @@
+/*
+ * 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;
+}
+
+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/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 e424cf6d8e9e..eee5af863b53 100644
--- a/drivers/mfd/twl4030-core.c
+++ b/drivers/mfd/twl4030-core.c
@@ -480,7 +480,6 @@ static int
add_children(struct twl4030_platform_data *pdata, unsigned long features)
{
struct device *child;
- struct device *usb_transceiver = NULL;
if (twl_has_bci() && pdata->bci && !(features & TPS_SUBSET)) {
child = add_child(3, "twl4030_bci",
@@ -532,16 +531,61 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
}
if (twl_has_usb() && pdata->usb) {
+
+ static struct regulator_consumer_supply usb1v5 = {
+ .supply = "usb1v5",
+ };
+ static struct regulator_consumer_supply usb1v8 = {
+ .supply = "usb1v8",
+ };
+ static struct regulator_consumer_supply usb3v1 = {
+ .supply = "usb3v1",
+ };
+
+ /* First add the regulators so that they can be used by transceiver */
+ if (twl_has_regulator()) {
+ /* this is a template that gets copied */
+ struct regulator_init_data usb_fixed = {
+ .constraints.valid_modes_mask =
+ REGULATOR_MODE_NORMAL
+ | REGULATOR_MODE_STANDBY,
+ .constraints.valid_ops_mask =
+ REGULATOR_CHANGE_MODE
+ | REGULATOR_CHANGE_STATUS,
+ };
+
+ child = add_regulator_linked(TWL4030_REG_VUSB1V5,
+ &usb_fixed, &usb1v5, 1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator_linked(TWL4030_REG_VUSB1V8,
+ &usb_fixed, &usb1v8, 1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ child = add_regulator_linked(TWL4030_REG_VUSB3V1,
+ &usb_fixed, &usb3v1, 1);
+ if (IS_ERR(child))
+ return PTR_ERR(child);
+
+ }
+
child = add_child(0, "twl4030_usb",
pdata->usb, sizeof(*pdata->usb),
true,
/* irq0 = USB_PRES, irq1 = USB */
pdata->irq_base + 8 + 2, pdata->irq_base + 4);
+
if (IS_ERR(child))
return PTR_ERR(child);
/* we need to connect regulators to this transceiver */
- usb_transceiver = child;
+ if (twl_has_regulator() && child) {
+ usb1v5.dev = child;
+ usb1v8.dev = child;
+ usb3v1.dev = child;
+ }
}
if (twl_has_watchdog()) {
@@ -580,47 +624,6 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
return PTR_ERR(child);
}
- if (twl_has_regulator() && usb_transceiver) {
- static struct regulator_consumer_supply usb1v5 = {
- .supply = "usb1v5",
- };
- static struct regulator_consumer_supply usb1v8 = {
- .supply = "usb1v8",
- };
- static struct regulator_consumer_supply usb3v1 = {
- .supply = "usb3v1",
- };
-
- /* this is a template that gets copied */
- struct regulator_init_data usb_fixed = {
- .constraints.valid_modes_mask =
- REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .constraints.valid_ops_mask =
- REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- };
-
- usb1v5.dev = usb_transceiver;
- usb1v8.dev = usb_transceiver;
- usb3v1.dev = usb_transceiver;
-
- child = add_regulator_linked(TWL4030_REG_VUSB1V5, &usb_fixed,
- &usb1v5, 1);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator_linked(TWL4030_REG_VUSB1V8, &usb_fixed,
- &usb1v8, 1);
- if (IS_ERR(child))
- return PTR_ERR(child);
-
- child = add_regulator_linked(TWL4030_REG_VUSB3V1, &usb_fixed,
- &usb3v1, 1);
- if (IS_ERR(child))
- return PTR_ERR(child);
- }
-
/* maybe add LDOs that are omitted on cost-reduced parts */
if (twl_has_regulator() && !(features & TPS_SUBSET)) {
child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2);
@@ -797,8 +800,6 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
status = -ENOMEM;
goto fail;
}
- strlcpy(twl->client->name, id->name,
- sizeof(twl->client->name));
}
mutex_init(&twl->xfer_lock);
}
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index fea9085fe52c..60c3988f3cf3 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -18,6 +18,7 @@
*/
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/errno.h>
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/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..498ab3ebd448 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -246,6 +246,16 @@ 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"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index f982d2ecfde7..b6245e46e285 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -20,6 +20,7 @@ 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-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/hpilo.c b/drivers/misc/hpilo.c
index 1ad27c6abcca..a92a3a742b43 100644
--- a/drivers/misc/hpilo.c
+++ b/drivers/misc/hpilo.c
@@ -18,6 +18,7 @@
#include <linux/device.h>
#include <linux/file.h>
#include <linux/cdev.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c
index 276d3fb68094..e2031739aa29 100644
--- a/drivers/misc/ibmasm/command.c
+++ b/drivers/misc/ibmasm/command.c
@@ -22,6 +22,7 @@
*
*/
+#include <linux/sched.h>
#include "ibmasm.h"
#include "lowlevel.h"
diff --git a/drivers/misc/ibmasm/event.c b/drivers/misc/ibmasm/event.c
index 68a0a5b94795..572d41ffc186 100644
--- a/drivers/misc/ibmasm/event.c
+++ b/drivers/misc/ibmasm/event.c
@@ -22,6 +22,7 @@
*
*/
+#include <linux/sched.h>
#include "ibmasm.h"
#include "lowlevel.h"
diff --git a/drivers/misc/ibmasm/r_heartbeat.c b/drivers/misc/ibmasm/r_heartbeat.c
index bec9e2c44bef..2de487ac788c 100644
--- a/drivers/misc/ibmasm/r_heartbeat.c
+++ b/drivers/misc/ibmasm/r_heartbeat.c
@@ -20,6 +20,7 @@
*
*/
+#include <linux/sched.h>
#include "ibmasm.h"
#include "dot_command.h"
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/phantom.c b/drivers/misc/phantom.c
index 90a95ce8dc34..04c27266f567 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -22,6 +22,7 @@
#include <linux/interrupt.h>
#include <linux/cdev.h>
#include <linux/phantom.h>
+#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <asm/atomic.h>
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/core/sdio_cis.c b/drivers/mmc/core/sdio_cis.c
index e1035c895808..f85dcd536508 100644
--- a/drivers/mmc/core/sdio_cis.c
+++ b/drivers/mmc/core/sdio_cis.c
@@ -29,6 +29,8 @@ static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
unsigned i, nr_strings;
char **buffer, *string;
+ /* Find all null-terminated (including zero length) strings in
+ the TPLLV1_INFO field. Trailing garbage is ignored. */
buf += 2;
size -= 2;
@@ -39,11 +41,8 @@ static int cistpl_vers_1(struct mmc_card *card, struct sdio_func *func,
if (buf[i] == 0)
nr_strings++;
}
-
- if (nr_strings < 4) {
- printk(KERN_WARNING "SDIO: ignoring broken CISTPL_VERS_1\n");
+ if (nr_strings == 0)
return 0;
- }
size = i;
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/pxamci.c b/drivers/mmc/host/pxamci.c
index 5e0b1529964d..b00d67319058 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -693,7 +693,7 @@ static int pxamci_probe(struct platform_device *pdev)
if (gpio_is_valid(gpio_ro)) {
ret = gpio_request(gpio_ro, "mmc card read only");
if (ret) {
- dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_power);
+ dev_err(&pdev->dev, "Failed requesting gpio_ro %d\n", gpio_ro);
goto err_gpio_ro;
}
gpio_direction_input(gpio_ro);
@@ -701,7 +701,7 @@ static int pxamci_probe(struct platform_device *pdev)
if (gpio_is_valid(gpio_cd)) {
ret = gpio_request(gpio_cd, "mmc card detect");
if (ret) {
- dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_power);
+ dev_err(&pdev->dev, "Failed requesting gpio_cd %d\n", gpio_cd);
goto err_gpio_cd;
}
gpio_direction_input(gpio_cd);
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/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 379c316f329e..d17ee6bdbd6c 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -21,6 +21,7 @@
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/math64.h>
+#include <linux/sched.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@@ -775,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/sst25l.c b/drivers/mtd/devices/sst25l.c
index c2baf3353f84..0a11721f146e 100644
--- a/drivers/mtd/devices/sst25l.c
+++ b/drivers/mtd/devices/sst25l.c
@@ -20,6 +20,7 @@
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/interrupt.h>
+#include <linux/sched.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 841e085ab74a..14be0755d7cd 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -486,6 +486,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/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/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index fdb97f3d30e9..d7a47574d21e 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;
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 2fda0b615246..8f8e87b7ed64 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -358,7 +358,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/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/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/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/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/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/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 712776089b46..e012c2e0825a 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
@@ -1741,6 +1741,7 @@ config KS8851
config KS8851_MLL
tristate "Micrel KS8851 MLL"
depends on HAS_IOMEM
+ select MII
help
This platform driver is for Micrel KS8851 Address/data bus
multiplexed network chip.
@@ -2482,6 +2483,8 @@ config S6GMAC
To compile this driver as a module, choose M here. The module
will be called s6gmac.
+source "drivers/net/stmmac/Kconfig"
+
endif # NETDEV_1000
#
@@ -3230,4 +3233,12 @@ config VIRTIO_NET
This is the virtual network driver for virtio. It can be used with
lguest or QEMU based VMMs (like KVM or Xen). Say Y or M.
+config VMXNET3
+ tristate "VMware VMXNET3 ethernet driver"
+ depends on PCI && X86 && INET
+ help
+ This driver supports VMware's vmxnet3 virtual ethernet NIC.
+ To compile this driver as a module, choose M here: the
+ module will be called vmxnet3.
+
endif # NETDEVICES
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index d866b8cf65d1..246323d7f161 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -2,6 +2,10 @@
# Makefile for the Linux network (ethercard) device drivers.
#
+obj-$(CONFIG_MII) += mii.o
+obj-$(CONFIG_MDIO) += mdio.o
+obj-$(CONFIG_PHYLIB) += phy/
+
obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o
obj-$(CONFIG_E1000) += e1000/
@@ -26,6 +30,7 @@ obj-$(CONFIG_TEHUTI) += tehuti.o
obj-$(CONFIG_ENIC) += enic/
obj-$(CONFIG_JME) += jme.o
obj-$(CONFIG_BE2NET) += benet/
+obj-$(CONFIG_VMXNET3) += vmxnet3/
gianfar_driver-objs := gianfar.o \
gianfar_ethtool.o \
@@ -95,15 +100,12 @@ obj-$(CONFIG_VIA_VELOCITY) += via-velocity.o
obj-$(CONFIG_ADAPTEC_STARFIRE) += starfire.o
obj-$(CONFIG_RIONET) += rionet.o
obj-$(CONFIG_SH_ETH) += sh_eth.o
+obj-$(CONFIG_STMMAC_ETH) += stmmac/
#
# end link order section
#
-obj-$(CONFIG_MII) += mii.o
-obj-$(CONFIG_MDIO) += mdio.o
-obj-$(CONFIG_PHYLIB) += phy/
-
obj-$(CONFIG_SUNDANCE) += sundance.o
obj-$(CONFIG_HAMACHI) += hamachi.o
obj-$(CONFIG_NET) += Space.o loopback.o
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 5f0b05c2d71f..d82a9a994753 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -1209,7 +1209,8 @@ static int __devinit ace_init(struct net_device *dev)
memset(ap->info, 0, sizeof(struct ace_info));
memset(ap->skb, 0, sizeof(struct ace_skb));
- if (ace_load_firmware(dev))
+ ecode = ace_load_firmware(dev);
+ if (ecode)
goto init_error;
ap->fw_running = 0;
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 fdf5937233fc..04f63c77071d 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -721,7 +721,7 @@ static inline void update_rx_stats(struct net_device *dev, u32 status)
ps->rx_errors++;
if (status & RX_MISSED_FRAME)
ps->rx_missed_errors++;
- if (status & (RX_OVERLEN | RX_OVERLEN | RX_LEN_ERROR))
+ if (status & (RX_OVERLEN | RX_RUNT | RX_LEN_ERROR))
ps->rx_length_errors++;
if (status & RX_CRC_ERROR)
ps->rx_crc_errors++;
@@ -794,8 +794,6 @@ static int au1000_rx(struct net_device *dev)
printk("rx len error\n");
if (status & RX_U_CNTRL_FRAME)
printk("rx u control frame\n");
- if (status & RX_MISSED_FRAME)
- printk("rx miss\n");
}
}
prxd->buff_stat = (u32)(pDB->dma_addr | RX_DMA_ENABLE);
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..4b61a9154222 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -181,7 +181,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 79d35d122c08..25b6602e464c 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -1118,6 +1118,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)
{
@@ -1129,7 +1188,6 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
spin_lock_bh(&adapter->mcc_lock);
wrb = wrb_from_mccq(adapter);
- req = embedded_payload(wrb);
sge = nonembedded_sgl(wrb);
be_wrb_hdr_prepare(wrb, cmd->size, false, 1);
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
index 8b4c2cb9ad62..a1e78cc3e171 100644
--- a/drivers/net/benet/be_cmds.h
+++ b/drivers/net/benet/be_cmds.h
@@ -62,7 +62,7 @@ enum {
MCC_STATUS_QUEUE_FLUSHING = 0x4,
/* The command is completing with a DMA error */
MCC_STATUS_DMA_FAILED = 0x5,
- MCC_STATUS_NOT_SUPPORTED = 0x66
+ MCC_STATUS_NOT_SUPPORTED = 66
};
#define CQE_STATUS_COMPL_MASK 0xFFFF
@@ -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;
@@ -764,6 +797,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 11445df3dbc0..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);
@@ -358,13 +392,14 @@ const struct ethtool_ops be_ethtool_ops = {
.get_rx_csum = be_get_rx_csum,
.set_rx_csum = be_set_rx_csum,
.get_tx_csum = ethtool_op_get_tx_csum,
- .set_tx_csum = ethtool_op_set_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_hw_csum,
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.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 2f9b50156e0c..e0f9d6477184 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;
@@ -197,7 +197,7 @@ void netdev_stats_update(struct be_adapter *adapter)
/* no space available in linux */
dev_stats->tx_dropped = 0;
- dev_stats->multicast = port_stats->tx_multicastframes;
+ dev_stats->multicast = port_stats->rx_multicast_frames;
dev_stats->collisions = 0;
/* detailed tx_errors */
@@ -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))
@@ -1899,8 +1895,8 @@ static void be_netdev_init(struct net_device *netdev)
struct be_adapter *adapter = netdev_priv(netdev);
netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
- NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM |
- NETIF_F_IPV6_CSUM | NETIF_F_GRO;
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_CSUM |
+ NETIF_F_GRO;
netdev->flags |= IFF_MULTICAST;
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_main.c b/drivers/net/bonding/bond_main.c
index 69c5b15e22da..feb03ad0d803 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)
{
}
@@ -4646,7 +4685,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 +4704,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 +4985,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 +5030,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 ff449de6f3c0..535b457f5d4c 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
+#include <linux/sched.h>
#include <linux/sysdev.h>
#include <linux/fs.h>
#include <linux/types.h>
@@ -1213,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,
@@ -1501,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..9c03c2ee074d 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;
@@ -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)
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..b13fd9114130 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -1087,7 +1087,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..39b99f57c265 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;
@@ -445,17 +452,30 @@ static void can_setup(struct net_device *dev)
/*
* 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..96d8be4253f8 100644
--- a/drivers/net/can/sja1000/sja1000.c
+++ b/drivers/net/can/sja1000/sja1000.c
@@ -565,7 +565,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/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c
index 3373560405ba..9dd076a626a5 100644
--- a/drivers/net/can/sja1000/sja1000_of_platform.c
+++ b/drivers/net/can/sja1000/sja1000_of_platform.c
@@ -213,6 +213,7 @@ static struct of_device_id __devinitdata sja1000_ofp_table[] = {
{.compatible = "nxp,sja1000"},
{},
};
+MODULE_DEVICE_TABLE(of, sja1000_ofp_table);
static struct of_platform_driver sja1000_ofp_driver = {
.owner = THIS_MODULE,
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
new file mode 100644
index 000000000000..23a7128e4eb7
--- /dev/null
+++ b/drivers/net/can/ti_hecc.c
@@ -0,0 +1,1002 @@
+/*
+ * 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 = netdev_alloc_skb(priv->ndev, sizeof(struct can_frame));
+ if (!skb) {
+ if (printk_ratelimit())
+ dev_err(priv->ndev->dev.parent,
+ "ti_hecc_rx_pkt: netdev_alloc_skb() failed\n");
+ return -ENOMEM;
+ }
+ skb->protocol = __constant_htons(ETH_P_CAN);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ mbx_mask = BIT(mbxno);
+ cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
+ 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 = netdev_alloc_skb(ndev, sizeof(struct can_frame));
+ if (!skb) {
+ if (printk_ratelimit())
+ dev_err(priv->ndev->dev.parent,
+ "ti_hecc_error: netdev_alloc_skb() failed\n");
+ return -ENOMEM;
+ }
+ skb->protocol = __constant_htons(ETH_P_CAN);
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ 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 (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..a65f56a9cd3d 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;
@@ -1012,7 +1012,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/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..b7f4ee40879c 100644
--- a/drivers/net/cxgb3/sge.c
+++ b/drivers/net/cxgb3/sge.c
@@ -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
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 65a2d0ba64e2..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)
@@ -333,6 +330,9 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1";
#define EMAC_DM646X_MAC_EOI_C0_RXEN (0x01)
#define EMAC_DM646X_MAC_EOI_C0_TXEN (0x02)
+/* EMAC Stats Clear Mask */
+#define EMAC_STATS_CLR_MASK (0xFFFFFFFF)
+
/** net_buf_obj: EMAC network bufferdata structure
*
* EMAC network buffer data structure
@@ -747,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 */
@@ -2105,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 */
@@ -2548,40 +2547,49 @@ static int emac_dev_stop(struct net_device *ndev)
static struct net_device_stats *emac_dev_getnetstats(struct net_device *ndev)
{
struct emac_priv *priv = netdev_priv(ndev);
+ u32 mac_control;
+ u32 stats_clear_mask;
/* update emac hardware stats and reset the registers*/
+ mac_control = emac_read(EMAC_MACCONTROL);
+
+ if (mac_control & EMAC_MACCONTROL_GMIIEN)
+ stats_clear_mask = EMAC_STATS_CLR_MASK;
+ else
+ stats_clear_mask = 0;
+
priv->net_dev_stats.multicast += emac_read(EMAC_RXMCASTFRAMES);
- emac_write(EMAC_RXMCASTFRAMES, EMAC_ALL_MULTI_REG_VALUE);
+ emac_write(EMAC_RXMCASTFRAMES, stats_clear_mask);
priv->net_dev_stats.collisions += (emac_read(EMAC_TXCOLLISION) +
emac_read(EMAC_TXSINGLECOLL) +
emac_read(EMAC_TXMULTICOLL));
- emac_write(EMAC_TXCOLLISION, EMAC_ALL_MULTI_REG_VALUE);
- emac_write(EMAC_TXSINGLECOLL, EMAC_ALL_MULTI_REG_VALUE);
- emac_write(EMAC_TXMULTICOLL, EMAC_ALL_MULTI_REG_VALUE);
+ emac_write(EMAC_TXCOLLISION, stats_clear_mask);
+ emac_write(EMAC_TXSINGLECOLL, stats_clear_mask);
+ emac_write(EMAC_TXMULTICOLL, stats_clear_mask);
priv->net_dev_stats.rx_length_errors += (emac_read(EMAC_RXOVERSIZED) +
emac_read(EMAC_RXJABBER) +
emac_read(EMAC_RXUNDERSIZED));
- emac_write(EMAC_RXOVERSIZED, EMAC_ALL_MULTI_REG_VALUE);
- emac_write(EMAC_RXJABBER, EMAC_ALL_MULTI_REG_VALUE);
- emac_write(EMAC_RXUNDERSIZED, EMAC_ALL_MULTI_REG_VALUE);
+ emac_write(EMAC_RXOVERSIZED, stats_clear_mask);
+ emac_write(EMAC_RXJABBER, stats_clear_mask);
+ emac_write(EMAC_RXUNDERSIZED, stats_clear_mask);
priv->net_dev_stats.rx_over_errors += (emac_read(EMAC_RXSOFOVERRUNS) +
emac_read(EMAC_RXMOFOVERRUNS));
- emac_write(EMAC_RXSOFOVERRUNS, EMAC_ALL_MULTI_REG_VALUE);
- emac_write(EMAC_RXMOFOVERRUNS, EMAC_ALL_MULTI_REG_VALUE);
+ emac_write(EMAC_RXSOFOVERRUNS, stats_clear_mask);
+ emac_write(EMAC_RXMOFOVERRUNS, stats_clear_mask);
priv->net_dev_stats.rx_fifo_errors += emac_read(EMAC_RXDMAOVERRUNS);
- emac_write(EMAC_RXDMAOVERRUNS, EMAC_ALL_MULTI_REG_VALUE);
+ emac_write(EMAC_RXDMAOVERRUNS, stats_clear_mask);
priv->net_dev_stats.tx_carrier_errors +=
emac_read(EMAC_TXCARRIERSENSE);
- emac_write(EMAC_TXCARRIERSENSE, EMAC_ALL_MULTI_REG_VALUE);
+ emac_write(EMAC_TXCARRIERSENSE, stats_clear_mask);
priv->net_dev_stats.tx_fifo_errors = emac_read(EMAC_TXUNDERRUN);
- emac_write(EMAC_TXUNDERRUN, EMAC_ALL_MULTI_REG_VALUE);
+ emac_write(EMAC_TXUNDERRUN, stats_clear_mask);
return &priv->net_dev_stats;
}
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index 9686c1fa28f1..7a3bdac84abe 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -237,6 +237,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ioport.h>
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/e100.c b/drivers/net/e100.c
index 679965c2bb86..fab9cd4a4f26 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -151,6 +151,7 @@
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
@@ -1839,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/82571.c b/drivers/net/e1000e/82571.c
index b53b40ba88a8..d1e0563a67df 100644
--- a/drivers/net/e1000e/82571.c
+++ b/drivers/net/e1000e/82571.c
@@ -1803,7 +1803,7 @@ struct e1000_info e1000_82574_info = {
| FLAG_HAS_AMT
| FLAG_HAS_CTRLEXT_ON_LOAD,
.pba = 20,
- .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN,
+ .max_hw_frame_size = DEFAULT_JUMBO,
.get_variants = e1000_get_variants_82571,
.mac_ops = &e82571_mac_ops,
.phy_ops = &e82_phy_ops_bm,
@@ -1820,7 +1820,7 @@ struct e1000_info e1000_82583_info = {
| FLAG_HAS_AMT
| FLAG_HAS_CTRLEXT_ON_LOAD,
.pba = 20,
- .max_hw_frame_size = DEFAULT_JUMBO,
+ .max_hw_frame_size = ETH_FRAME_LEN + ETH_FCS_LEN,
.get_variants = e1000_get_variants_82571,
.mac_ops = &e82571_mac_ops,
.phy_ops = &e82_phy_ops_bm,
diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h
index 981936c1fb46..1211df9ae883 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;
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/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/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/eql.c b/drivers/net/eql.c
index d4d9a3eda695..f5b96cadeb25 100644
--- a/drivers/net/eql.c
+++ b/drivers/net/eql.c
@@ -111,6 +111,7 @@
* Sorry, I had to rewrite most of this for 2.5.x -DaveM
*/
+#include <linux/capability.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c
index b7311bc00258..3cb10f1338a8 100644
--- a/drivers/net/ethoc.c
+++ b/drivers/net/ethoc.c
@@ -17,8 +17,13 @@
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
+#include <linux/sched.h>
#include <net/ethoc.h>
+static int buffer_size = 0x8000; /* 32 KBytes */
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
+
/* register offsets */
#define MODER 0x00
#define INT_SOURCE 0x04
@@ -167,6 +172,7 @@
* struct ethoc - driver-private device structure
* @iobase: pointer to I/O memory region
* @membase: pointer to buffer memory region
+ * @dma_alloc: dma allocated buffer size
* @num_tx: number of send buffers
* @cur_tx: last send buffer written
* @dty_tx: last buffer actually sent
@@ -185,6 +191,7 @@
struct ethoc {
void __iomem *iobase;
void __iomem *membase;
+ int dma_alloc;
unsigned int num_tx;
unsigned int cur_tx;
@@ -284,7 +291,7 @@ static int ethoc_init_ring(struct ethoc *dev)
dev->cur_rx = 0;
/* setup transmission buffers */
- bd.addr = 0;
+ bd.addr = virt_to_phys(dev->membase);
bd.stat = TX_BD_IRQ | TX_BD_CRC;
for (i = 0; i < dev->num_tx; i++) {
@@ -295,7 +302,6 @@ static int ethoc_init_ring(struct ethoc *dev)
bd.addr += ETHOC_BUFSIZ;
}
- bd.addr = dev->num_tx * ETHOC_BUFSIZ;
bd.stat = RX_BD_EMPTY | RX_BD_IRQ;
for (i = 0; i < dev->num_rx; i++) {
@@ -399,9 +405,13 @@ 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 = netdev_alloc_skb_ip_align(dev, size);
+
if (likely(skb)) {
- void *src = priv->membase + bd.addr;
+ void *src = phys_to_virt(bd.addr);
memcpy_fromio(skb_put(skb, size), src, size);
skb->protocol = eth_type_trans(skb, dev);
priv->stats.rx_packets++;
@@ -653,9 +663,10 @@ static int ethoc_open(struct net_device *dev)
if (ret)
return ret;
- /* calculate the number of TX/RX buffers */
- num_bd = (dev->mem_end - dev->mem_start + 1) / ETHOC_BUFSIZ;
- priv->num_tx = min(min_tx, num_bd / 4);
+ /* calculate the number of TX/RX buffers, maximum 128 supported */
+ num_bd = min_t(unsigned int,
+ 128, (dev->mem_end - dev->mem_start + 1) / ETHOC_BUFSIZ);
+ priv->num_tx = max(min_tx, num_bd / 4);
priv->num_rx = num_bd - priv->num_tx;
ethoc_write(priv, TX_BD_NUM, priv->num_tx);
@@ -823,7 +834,7 @@ static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
else
bd.stat &= ~TX_BD_PAD;
- dest = priv->membase + bd.addr;
+ dest = phys_to_virt(bd.addr);
memcpy_toio(dest, skb->data, skb->len);
bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK);
@@ -903,22 +914,19 @@ static int ethoc_probe(struct platform_device *pdev)
/* obtain buffer memory space */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res) {
- dev_err(&pdev->dev, "cannot obtain memory space\n");
- ret = -ENXIO;
- goto free;
- }
-
- mem = devm_request_mem_region(&pdev->dev, res->start,
+ if (res) {
+ mem = devm_request_mem_region(&pdev->dev, res->start,
res->end - res->start + 1, res->name);
- if (!mem) {
- dev_err(&pdev->dev, "cannot request memory space\n");
- ret = -ENXIO;
- goto free;
+ if (!mem) {
+ dev_err(&pdev->dev, "cannot request memory space\n");
+ ret = -ENXIO;
+ goto free;
+ }
+
+ netdev->mem_start = mem->start;
+ netdev->mem_end = mem->end;
}
- netdev->mem_start = mem->start;
- netdev->mem_end = mem->end;
/* obtain device IRQ number */
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -933,6 +941,7 @@ static int ethoc_probe(struct platform_device *pdev)
/* setup driver-private data */
priv = netdev_priv(netdev);
priv->netdev = netdev;
+ priv->dma_alloc = 0;
priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr,
mmio->end - mmio->start + 1);
@@ -942,12 +951,27 @@ static int ethoc_probe(struct platform_device *pdev)
goto error;
}
- priv->membase = devm_ioremap_nocache(&pdev->dev, netdev->mem_start,
- mem->end - mem->start + 1);
- if (!priv->membase) {
- dev_err(&pdev->dev, "cannot remap memory space\n");
- ret = -ENXIO;
- goto error;
+ if (netdev->mem_end) {
+ priv->membase = devm_ioremap_nocache(&pdev->dev,
+ netdev->mem_start, mem->end - mem->start + 1);
+ if (!priv->membase) {
+ dev_err(&pdev->dev, "cannot remap memory space\n");
+ ret = -ENXIO;
+ goto error;
+ }
+ } else {
+ /* Allocate buffer memory */
+ priv->membase = dma_alloc_coherent(NULL,
+ buffer_size, (void *)&netdev->mem_start,
+ GFP_KERNEL);
+ if (!priv->membase) {
+ dev_err(&pdev->dev, "cannot allocate %dB buffer\n",
+ buffer_size);
+ ret = -ENOMEM;
+ goto error;
+ }
+ netdev->mem_end = netdev->mem_start + buffer_size;
+ priv->dma_alloc = buffer_size;
}
/* Allow the platform setup code to pass in a MAC address. */
@@ -1034,6 +1058,9 @@ free_mdio:
kfree(priv->mdio->irq);
mdiobus_free(priv->mdio);
free:
+ if (priv->dma_alloc)
+ dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
+ netdev->mem_start);
free_netdev(netdev);
out:
return ret;
@@ -1059,7 +1086,9 @@ static int ethoc_remove(struct platform_device *pdev)
kfree(priv->mdio->irq);
mdiobus_free(priv->mdio);
}
-
+ if (priv->dma_alloc)
+ dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
+ netdev->mem_start);
unregister_netdev(netdev);
free_netdev(netdev);
}
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index b2a5ec8f3721..dd4ba01fd92d 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -145,6 +145,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ioport.h>
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index c40113f58963..66dace6d324f 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -759,12 +759,6 @@ static void mpc52xx_fec_reset(struct net_device *dev)
mpc52xx_fec_hw_init(dev);
- if (priv->phydev) {
- phy_stop(priv->phydev);
- phy_write(priv->phydev, MII_BMCR, BMCR_RESET);
- phy_start(priv->phydev);
- }
-
bcom_fec_rx_reset(priv->rx_dmatsk);
bcom_fec_tx_reset(priv->tx_dmatsk);
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c
index 31e6d62b785d..ee0f3c6d3f88 100644
--- a/drivers/net/fec_mpc52xx_phy.c
+++ b/drivers/net/fec_mpc52xx_phy.c
@@ -155,6 +155,7 @@ static struct of_device_id mpc52xx_fec_mdio_match[] = {
{ .compatible = "mpc5200b-fec-phy", },
{}
};
+MODULE_DEVICE_TABLE(of, mpc52xx_fec_mdio_match);
struct of_platform_driver mpc52xx_fec_mdio_driver = {
.name = "mpc5200b-fec-phy",
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 0a1c2bb27d4d..e1da4666f204 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -49,6 +49,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/timer.h>
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 2bc2d2b20644..ec2f5034457f 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -1110,6 +1110,7 @@ static struct of_device_id fs_enet_match[] = {
#endif
{}
};
+MODULE_DEVICE_TABLE(of, fs_enet_match);
static struct of_platform_driver fs_enet_driver = {
.name = "fs_enet",
diff --git a/drivers/net/fs_enet/mii-bitbang.c b/drivers/net/fs_enet/mii-bitbang.c
index 93b481b0e3c7..24ff9f43a62b 100644
--- a/drivers/net/fs_enet/mii-bitbang.c
+++ b/drivers/net/fs_enet/mii-bitbang.c
@@ -221,6 +221,7 @@ static struct of_device_id fs_enet_mdio_bb_match[] = {
},
{},
};
+MODULE_DEVICE_TABLE(of, fs_enet_mdio_bb_match);
static struct of_platform_driver fs_enet_bb_mdio_driver = {
.name = "fsl-bb-mdio",
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index a2d69c1cd07e..96eba4280c5c 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -219,6 +219,7 @@ static struct of_device_id fs_enet_mdio_fec_match[] = {
#endif
{},
};
+MODULE_DEVICE_TABLE(of, fs_enet_mdio_fec_match);
static struct of_platform_driver fs_enet_fec_mdio_driver = {
.name = "fsl-fec-mdio",
diff --git a/drivers/net/fsl_pq_mdio.c b/drivers/net/fsl_pq_mdio.c
index d167090248e2..6ac464866972 100644
--- a/drivers/net/fsl_pq_mdio.c
+++ b/drivers/net/fsl_pq_mdio.c
@@ -407,6 +407,7 @@ static struct of_device_id fsl_pq_mdio_match[] = {
},
{},
};
+MODULE_DEVICE_TABLE(of, fsl_pq_mdio_match);
static struct of_platform_driver fsl_pq_mdio_driver = {
.name = "fsl-pq_mdio",
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 1e5289ffef6f..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);
-
- lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT);
-
- if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1)
- lstatus |= BD_LFLAG(RXBD_WRAP);
-
- eieio();
+ dma_addr_t buf;
- 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);
}
@@ -2325,9 +2397,6 @@ static irqreturn_t gfar_error(int irq, void *dev_id)
return IRQ_HANDLED;
}
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:fsl-gianfar");
-
static struct of_device_id gfar_match[] =
{
{
@@ -2336,6 +2405,7 @@ static struct of_device_id gfar_match[] =
},
{},
};
+MODULE_DEVICE_TABLE(of, gfar_match);
/* Structure for a device driver */
static struct of_platform_driver gfar_driver = {
@@ -2344,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 1d5064a09aca..c9ac46118e6f 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -145,6 +145,7 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (5*HZ)
+#include <linux/capability.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -406,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
@@ -1151,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 |
@@ -1195,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 7bcaf7c66243..a3c0dc9d8b98 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -44,6 +44,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/workqueue.h>
#include <linux/fs.h>
@@ -595,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/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index aa4488e871b2..ed60fd664273 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -71,6 +71,7 @@
/*****************************************************************************/
+#include <linux/capability.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/string.h>
diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
index 88c593596020..1686f6dcbbce 100644
--- a/drivers/net/hamradio/baycom_ser_hdx.c
+++ b/drivers/net/hamradio/baycom_ser_hdx.c
@@ -61,6 +61,7 @@
/*****************************************************************************/
+#include <linux/capability.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/string.h>
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index 0013c409782c..91c5790c9581 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -42,6 +42,7 @@
/*****************************************************************************/
+#include <linux/capability.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/net.h>
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index a9a1a99f02dd..dd8665138062 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -98,6 +98,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ioport.h>
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c
index 89c82c5e63e4..af117c626e73 100644
--- a/drivers/net/ibm_newemac/core.c
+++ b/drivers/net/ibm_newemac/core.c
@@ -24,6 +24,7 @@
*
*/
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
@@ -443,7 +444,7 @@ static u32 __emac_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_s
ret |= EMAC_MR1_TFS_2K;
break;
default:
- printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+ printk(KERN_WARNING "%s: Unknown Tx FIFO size %d\n",
dev->ndev->name, tx_size);
}
@@ -470,6 +471,9 @@ static u32 __emac4_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_
DBG2(dev, "__emac4_calc_base_mr1" NL);
switch(tx_size) {
+ case 16384:
+ ret |= EMAC4_MR1_TFS_16K;
+ break;
case 4096:
ret |= EMAC4_MR1_TFS_4K;
break;
@@ -477,7 +481,7 @@ static u32 __emac4_calc_base_mr1(struct emac_instance *dev, int tx_size, int rx_
ret |= EMAC4_MR1_TFS_2K;
break;
default:
- printk(KERN_WARNING "%s: Unknown Rx FIFO size %d\n",
+ printk(KERN_WARNING "%s: Unknown Tx FIFO size %d\n",
dev->ndev->name, tx_size);
}
@@ -2145,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,
@@ -2178,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);
}
@@ -2198,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,
@@ -2985,6 +2991,7 @@ static struct of_device_id emac_match[] =
},
{},
};
+MODULE_DEVICE_TABLE(of, emac_match);
static struct of_platform_driver emac_driver = {
.name = "emac",
diff --git a/drivers/net/ibm_newemac/emac.h b/drivers/net/ibm_newemac/emac.h
index 0afc2cf5c52b..d34adf99fc6a 100644
--- a/drivers/net/ibm_newemac/emac.h
+++ b/drivers/net/ibm_newemac/emac.h
@@ -153,6 +153,7 @@ struct emac_regs {
#define EMAC4_MR1_RFS_16K 0x00280000
#define EMAC4_MR1_TFS_2K 0x00020000
#define EMAC4_MR1_TFS_4K 0x00030000
+#define EMAC4_MR1_TFS_16K 0x00050000
#define EMAC4_MR1_TR 0x00008000
#define EMAC4_MR1_MWSW_001 0x00001000
#define EMAC4_MR1_JPSM 0x00000800
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 d004c359244c..ab84fcf8ccfe 100644
--- a/drivers/net/igb/igb_ethtool.c
+++ b/drivers/net/igb/igb_ethtool.c
@@ -34,17 +34,26 @@
#include <linux/interrupt.h>
#include <linux/if_ether.h>
#include <linux/ethtool.h>
+#include <linux/sched.h>
#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) },
@@ -54,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) },
@@ -1957,10 +1966,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..bc606f8b61aa 100644
--- a/drivers/net/igbvf/ethtool.c
+++ b/drivers/net/igbvf/ethtool.c
@@ -363,16 +363,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 +470,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 +530,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/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 38bf7cf2256d..c412e8026173 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -232,8 +232,11 @@ static int sa1100_irda_startup(struct sa1100_irda *si)
/*
* Ensure that the ports for this device are setup correctly.
*/
- if (si->pdata->startup)
- si->pdata->startup(si->dev);
+ if (si->pdata->startup) {
+ ret = si->pdata->startup(si->dev);
+ if (ret)
+ return ret;
+ }
/*
* Configure PPC for IRDA - we want to drive TXD2 low.
diff --git a/drivers/net/irda/toim3232-sir.c b/drivers/net/irda/toim3232-sir.c
index fcf287b749db..99e1ec02a011 100644
--- a/drivers/net/irda/toim3232-sir.c
+++ b/drivers/net/irda/toim3232-sir.c
@@ -120,6 +120,7 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/sched.h>
#include <net/irda/irda.h>
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 2ec58dcdb82b..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;
}
}
@@ -330,11 +340,14 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw)
switch (hw->device_id) {
case IXGBE_DEV_ID_82599_KX4:
+ case IXGBE_DEV_ID_82599_KX4_MEZZ:
+ case IXGBE_DEV_ID_82599_COMBO_BACKPLANE:
case IXGBE_DEV_ID_82599_XAUI_LOM:
/* Default device ID is mezzanine card KX/KX4 */
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:
@@ -477,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);
@@ -565,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
@@ -667,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..08eccf418c67 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)},
@@ -929,10 +937,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 28fbb9d281f9..4c8a44919705 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -97,8 +97,14 @@ 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),
board_82599 },
+ {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_COMBO_BACKPLANE),
+ board_82599 },
/* required last entry */
{0, }
@@ -368,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);
}
@@ -610,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,
@@ -705,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;
@@ -876,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;
}
@@ -4399,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;
@@ -4518,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;
}
/**
@@ -5296,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 7c93e923bf2e..1cab53eb22f3 100644
--- a/drivers/net/ixgbe/ixgbe_type.h
+++ b/drivers/net/ixgbe/ixgbe_type.h
@@ -49,9 +49,12 @@
#define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM 0x10E1
#define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4
#define IXGBE_DEV_ID_82599_KX4 0x10F7
+#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
/* General Registers */
#define IXGBE_CTRL 0x00000
@@ -2169,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,
@@ -2429,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/enp2611.c b/drivers/net/ixp2000/enp2611.c
index b02a981c87a8..34a6cfd17930 100644
--- a/drivers/net/ixp2000/enp2611.c
+++ b/drivers/net/ixp2000/enp2611.c
@@ -119,24 +119,9 @@ static struct ixp2400_msf_parameters enp2611_msf_parameters =
}
};
-struct enp2611_ixpdev_priv
-{
- struct ixpdev_priv ixpdev_priv;
- struct net_device_stats stats;
-};
-
static struct net_device *nds[3];
static struct timer_list link_check_timer;
-static struct net_device_stats *enp2611_get_stats(struct net_device *dev)
-{
- struct enp2611_ixpdev_priv *ip = netdev_priv(dev);
-
- pm3386_get_stats(ip->ixpdev_priv.channel, &(ip->stats));
-
- return &(ip->stats);
-}
-
/* @@@ Poll the SFP moddef0 line too. */
/* @@@ Try to use the pm3386 DOOL interrupt as well. */
static void enp2611_check_link_status(unsigned long __dummy)
@@ -203,14 +188,13 @@ static int __init enp2611_init_module(void)
ports = pm3386_port_count();
for (i = 0; i < ports; i++) {
- nds[i] = ixpdev_alloc(i, sizeof(struct enp2611_ixpdev_priv));
+ nds[i] = ixpdev_alloc(i, sizeof(struct ixpdev_priv));
if (nds[i] == NULL) {
while (--i >= 0)
free_netdev(nds[i]);
return -ENOMEM;
}
- nds[i]->get_stats = enp2611_get_stats;
pm3386_init_port(i);
pm3386_get_mac(i, nds[i]->dev_addr);
}
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index 127243461a51..e9d9d595e1b7 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -21,6 +21,7 @@
#include "ixp2400_tx.ucode"
#include "ixpdev_priv.h"
#include "ixpdev.h"
+#include "pm3386.h"
#define DRV_MODULE_VERSION "0.2"
@@ -108,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]);
@@ -271,6 +271,15 @@ static int ixpdev_close(struct net_device *dev)
return 0;
}
+static struct net_device_stats *ixpdev_get_stats(struct net_device *dev)
+{
+ struct ixpdev_priv *ip = netdev_priv(dev);
+
+ pm3386_get_stats(ip->channel, &(dev->stats));
+
+ return &(dev->stats);
+}
+
static const struct net_device_ops ixpdev_netdev_ops = {
.ndo_open = ixpdev_open,
.ndo_stop = ixpdev_close,
@@ -278,6 +287,7 @@ static const struct net_device_ops ixpdev_netdev_ops = {
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
.ndo_set_mac_address = eth_mac_addr,
+ .ndo_get_stats = ixpdev_get_stats,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = ixpdev_poll_controller,
#endif
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/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/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 3dd481e77f92..291a505fd4fc 100644
--- a/drivers/net/mlx4/main.c
+++ b/drivers/net/mlx4/main.c
@@ -1282,6 +1282,8 @@ 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..29c9fe2951e0 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -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;
@@ -1821,7 +1820,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 +2990,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..1bdb8f4a3c86 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -543,13 +543,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;
@@ -1086,6 +1089,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 +1119,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 +1180,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 +1202,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;
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..34613503262f 100644
--- a/drivers/net/netxen/netxen_nic_hdr.h
+++ b/drivers/net/netxen/netxen_nic_hdr.h
@@ -661,40 +661,47 @@ 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(i) (0x10+(4*(i)))
+#define MIU_TEST_AGT_RDDATA_LO (0x18)
+#define MIU_TEST_AGT_RDDATA_HI (0x1c)
+#define MIU_TEST_AGT_RDDATA(i) (0x18+(4*(i)))
+
+#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
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 32314000dfcd..d067bee87cd5 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -41,6 +41,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)
{
@@ -1046,46 +1051,34 @@ 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;
}
/*
@@ -1140,20 +1133,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 +1169,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 +1198,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;
@@ -1232,12 +1227,12 @@ netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter, ulong off, u32 data)
}
if (rv == 1) {
- write_lock_irqsave(&adapter->adapter_lock, flags);
+ 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);
+ write_unlock_irqrestore(&adapter->ahw.crb_lock, flags);
} else
writel(data, (void __iomem *)off);
@@ -1262,91 +1257,25 @@ netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter, ulong off)
}
if (rv == 1) {
- write_lock_irqsave(&adapter->adapter_lock, flags);
+ 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);
+ write_unlock_irqrestore(&adapter->ahw.crb_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;
- }
-
- 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;
-}
-
/* 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 +1283,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 +1318,382 @@ 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;
+ }
- 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;
+ return -EIO;
+}
- } 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;
+static int
+netxen_nic_pci_set_window_2M(struct netxen_adapter *adapter,
+ u64 addr, u32 *start)
+{
+ u32 win_read, window;
+ struct pci_dev *pdev = adapter->pdev;
- } 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);
+ if ((addr & 0x00ff800) == 0xff800) {
+ if (printk_ratelimit())
+ dev_warn(&pdev->dev, "QM access not handled\n");
+ return -EIO;
+ }
+
+ window = OCM_WIN(addr);
+ writel(window, adapter->ahw.ocm_win_crb);
+ win_read = readl(adapter->ahw.ocm_win_crb);
+ if ((win_read >> 7) != window) {
+ if (printk_ratelimit())
+ dev_warn(&pdev->dev, "failed to set OCM window\n");
+ return -EIO;
+ }
+
+ 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));
-
- for (j = 0; j < MAX_CTL_CHECK; j++) {
- temp = readl(
- (mem_crb+MIU_TEST_AGT_CTRL));
- if ((temp & MIU_TA_CTL_BUSY) == 0)
- break;
- }
+ spin_lock(&adapter->ahw.mem_lock);
+ netxen_nic_pci_set_crbwindow_128M(adapter, 0);
- if (j >= MAX_CTL_CHECK) {
- if (printk_ratelimit())
- dev_err(&adapter->pdev->dev,
- "failed to read through agent\n");
- 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));
- 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));
- }
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = readl(mem_crb + TEST_AGT_CTRL);
+ if ((temp & TA_CTL_BUSY) == 0)
+ break;
}
- 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 j, ret;
+ u32 temp, off8;
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;
- }
- }
+ off8 = off & MIU_TEST_AGT_ADDR_MASK;
- 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;
- }
+ spin_lock(&adapter->ahw.mem_lock);
- word[0] &= ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
- word[0] |= tmpw << (off0 * 8);
+ writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO));
+ writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI));
+ writel(data & 0xffffffff, mem_crb + MIU_TEST_AGT_WRDATA_LO);
+ writel((data >> 32) & 0xffffffff, mem_crb + MIU_TEST_AGT_WRDATA_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));
- if (loop == 2) {
- word[1] &= ~(~0ULL << (sz[1] * 8));
- word[1] |= tmpw >> (sz[0] * 8);
+ for (j = 0; j < MAX_CTL_CHECK; j++) {
+ temp = readl(mem_crb + TEST_AGT_CTRL);
+ if ((temp & TA_CTL_BUSY) == 0)
+ break;
}
- /*
- * 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);
- */
-
- 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);
-
- 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;
+
+ spin_unlock(&adapter->ahw.mem_lock);
- /*
- * netxen_nic_pci_change_crbwindow_128M(adapter, 1);
- * write_unlock_irqrestore(&adapter->adapter_lock, flags);
- */
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;
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;
+ off8 = off & MIU_TEST_AGT_ADDR_MASK;
- /*
- * 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);
- */
+ spin_lock(&adapter->ahw.mem_lock);
- 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);
-
- 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));
+ temp = readl(mem_crb + MIU_TEST_AGT_RDDATA_HI);
+ val = (u64)temp << 32;
+ val |= readl(mem_crb + MIU_TEST_AGT_RDDATA_LO);
+ *data = val;
+ ret = 0;
}
- 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;
- }
- return 0;
+ spin_unlock(&adapter->ahw.mem_lock);
+
+ return ret;
}
void
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 91c2bc61c8eb..83387c791d5f 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -702,7 +702,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 +719,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 +733,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;
@@ -1510,10 +1513,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 b5aa974827e5..5bc8520e3e15 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -73,6 +73,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);
@@ -595,7 +597,8 @@ netxen_setup_pci_map(struct netxen_adapter *adapter)
void __iomem *mem_ptr2 = NULL;
void __iomem *db_ptr = NULL;
- unsigned long mem_base, mem_len, db_base, db_len = 0, pci_len0 = 0;
+ resource_size_t mem_base, db_base;
+ unsigned long mem_len, db_len = 0, pci_len0 = 0;
struct pci_dev *pdev = adapter->pdev;
int pci_func = adapter->ahw.pci_func;
@@ -606,14 +609,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) {
@@ -622,6 +623,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 -
@@ -634,19 +636,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;
}
@@ -660,6 +649,11 @@ netxen_setup_pci_map(struct netxen_adapter *adapter)
adapter->ahw.pci_base1 = mem_ptr1;
adapter->ahw.pci_base2 = mem_ptr2;
+ if (!NX_IS_REVISION_P2(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;
@@ -1249,7 +1243,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);
@@ -1314,6 +1310,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:
@@ -1366,6 +1364,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);
@@ -1446,7 +1446,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) {
@@ -1714,7 +1715,7 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
/* 4 fragments per cmd des */
no_of_desc = (frag_count + 3) >> 2;
- if (unlikely(no_of_desc + 2) > netxen_tx_avail(tx_ring)) {
+ if (unlikely(no_of_desc + 2 > netxen_tx_avail(tx_ring))) {
netif_stop_queue(netdev);
return NETDEV_TX_BUSY;
}
@@ -1923,7 +1924,7 @@ request_reset:
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));
@@ -2337,6 +2338,160 @@ 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 void
netxen_create_sysfs_entries(struct netxen_adapter *adapter)
{
@@ -2362,6 +2517,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)
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index f9364d0678f2..1d1e657991d2 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -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/ns83820.c b/drivers/net/ns83820.c
index c594e1946476..57fd483dbb1f 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -111,6 +111,7 @@
#include <linux/compiler.h>
#include <linux/prefetch.h>
#include <linux/ethtool.h>
+#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/if_vlan.h>
#include <linux/rtnetlink.h>
diff --git a/drivers/net/pasemi_mac_ethtool.c b/drivers/net/pasemi_mac_ethtool.c
index 064a4fe1dd90..fefa79e34b95 100644
--- a/drivers/net/pasemi_mac_ethtool.c
+++ b/drivers/net/pasemi_mac_ethtool.c
@@ -71,9 +71,25 @@ pasemi_mac_ethtool_get_settings(struct net_device *netdev,
struct pasemi_mac *mac = netdev_priv(netdev);
struct phy_device *phydev = mac->phydev;
+ if (!phydev)
+ return -EOPNOTSUPP;
+
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)
@@ -147,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 ee8ad3e180dd..b58965a2b3ae 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -251,6 +251,7 @@ static void el3_tx_timeout(struct net_device *dev);
static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops netdev_ethtool_ops;
static void set_rx_mode(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
static void tc574_detach(struct pcmcia_device *p_dev);
@@ -266,7 +267,7 @@ static const struct net_device_ops el3_netdev_ops = {
.ndo_tx_timeout = el3_tx_timeout,
.ndo_get_stats = el3_get_stats,
.ndo_do_ioctl = el3_ioctl,
- .ndo_set_multicast_list = set_rx_mode,
+ .ndo_set_multicast_list = set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
@@ -1161,6 +1162,16 @@ static void set_rx_mode(struct net_device *dev)
outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
}
+static void set_multicast_list(struct net_device *dev)
+{
+ struct el3_private *lp = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&lp->window_lock, flags);
+ set_rx_mode(dev);
+ spin_unlock_irqrestore(&lp->window_lock, flags);
+}
+
static int el3_close(struct net_device *dev)
{
unsigned int ioaddr = dev->base_addr;
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 474876c879cb..bd3447f04902 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -1754,14 +1754,14 @@ static struct pcmcia_device_id pcnet_ids[] = {
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"),
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"),
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"),
- PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
- PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
- PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "DP83903.cis"),
+ PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"),
+ PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"),
+ PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "cis/DP83903.cis"),
PCMCIA_DEVICE_CIS_MANF_CARD(0xc00f, 0x0002, "cis/LA-PCM.cis"),
PCMCIA_DEVICE_CIS_PROD_ID12("KTI", "PE520 PLUS", 0xad180345, 0x9d58d392, "PE520.cis"),
- PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "NE2K.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "cis/NE2K.cis"),
PCMCIA_DEVICE_CIS_PROD_ID12("PMX ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "PE-200.cis"),
- PCMCIA_DEVICE_CIS_PROD_ID12("TAMARACK", "Ethernet", 0xcf434fba, 0x00b2e941, "tamarack.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID12("TAMARACK", "Ethernet", 0xcf434fba, 0x00b2e941, "cis/tamarack.cis"),
PCMCIA_DEVICE_PROD_ID12("Ethernet", "CF Size PC Card", 0x00b2e941, 0x43ac239b),
PCMCIA_DEVICE_PROD_ID123("Fast Ethernet", "CF Size PC Card", "1.0",
0xb4be14e3, 0x43ac239b, 0x0877b627),
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 6d28b18e7e28..c1b3f09f452c 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -31,6 +31,7 @@ static const char *const version =
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/ioport.h>
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
index 250e10f2c35b..8659d341e769 100644
--- a/drivers/net/phy/mdio-gpio.c
+++ b/drivers/net/phy/mdio-gpio.c
@@ -238,6 +238,7 @@ static struct of_device_id mdio_ofgpio_match[] = {
},
{},
};
+MODULE_DEVICE_TABLE(of, mdio_ofgpio_match);
static struct of_platform_driver mdio_ofgpio_driver = {
.name = "mdio-gpio",
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/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/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 30d5585beeee..421471790601 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -9,6 +9,7 @@
#include <linux/pci.h>
#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
/*
* General definitions...
@@ -53,7 +54,8 @@
#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 SMALL_BUFFER_SIZE 512
+#define SMALL_BUF_MAP_SIZE (SMALL_BUFFER_SIZE / 2)
#define LARGE_BUFFER_SIZE PAGE_SIZE
#define MAX_SPLIT_SIZE 1023
#define QLGE_SB_PAD 32
@@ -135,9 +137,9 @@ enum {
RST_FO_TFO = (1 << 0),
RST_FO_RR_MASK = 0x00060000,
RST_FO_RR_CQ_CAM = 0x00000000,
- RST_FO_RR_DROP = 0x00000001,
- RST_FO_RR_DQ = 0x00000002,
- RST_FO_RR_RCV_FUNC_CQ = 0x00000003,
+ RST_FO_RR_DROP = 0x00000002,
+ RST_FO_RR_DQ = 0x00000004,
+ RST_FO_RR_RCV_FUNC_CQ = 0x00000006,
RST_FO_FRB = (1 << 12),
RST_FO_MOP = (1 << 13),
RST_FO_REG = (1 << 14),
@@ -802,6 +804,12 @@ enum {
MB_CMD_SET_PORT_CFG = 0x00000122,
MB_CMD_GET_PORT_CFG = 0x00000123,
MB_CMD_GET_LINK_STS = 0x00000124,
+ 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),
+ MB_CMD_GET_MGMNT_TFK_CTL = 0x00000161, /* Get Mgmnt Traffic Control */
+ MB_GET_MPI_TFK_STOPPED = (1 << 0),
+ MB_GET_MPI_TFK_FIFO_EMPTY = (1 << 1),
/* Mailbox Command Status. */
MB_CMD_STS_GOOD = 0x00004000, /* Success. */
@@ -1167,7 +1175,7 @@ struct ricb {
#define RSS_RI6 0x40
#define RSS_RT6 0x80
__le16 mask;
- __le32 hash_cq_id[256];
+ u8 hash_cq_id[1024];
__le32 ipv6_hash_key[10];
__le32 ipv4_hash_key[4];
} __attribute((packed));
@@ -1355,6 +1363,27 @@ 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;
};
/*
@@ -1477,7 +1506,6 @@ struct ql_adapter {
u32 mailbox_in;
u32 mailbox_out;
struct mbox_params idc_mbc;
- struct mutex mpi_mutex;
int tx_ring_size;
int rx_ring_size;
@@ -1516,7 +1544,6 @@ struct ql_adapter {
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;
@@ -1606,6 +1633,8 @@ int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data);
int ql_mb_about_fw(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_wait_fifo_empty(struct ql_adapter *qdev);
#if 1
#define QL_ALL_DUMP
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index 68f9bd280f86..aac6c6f19a21 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -45,7 +45,6 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
if (!netif_running(qdev->ndev))
return status;
- spin_lock(&qdev->hw_lock);
/* Skip the default queue, and update the outbound handler
* queues if they changed.
*/
@@ -92,7 +91,6 @@ static int ql_update_ring_coalescing(struct ql_adapter *qdev)
}
}
exit:
- spin_unlock(&qdev->hw_lock);
return status;
}
@@ -134,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:
@@ -187,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)
@@ -259,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,
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 3d0efea32111..817613919b51 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -34,7 +34,6 @@
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/skbuff.h>
-#include <linux/rtnetlink.h>
#include <linux/if_vlan.h>
#include <linux/delay.h>
#include <linux/mm.h>
@@ -321,6 +320,37 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
switch (type) {
case MAC_ADDR_TYPE_MULTI_MAC:
+ {
+ u32 upper = (addr[0] << 8) | addr[1];
+ u32 lower = (addr[2] << 24) | (addr[3] << 16) |
+ (addr[4] << 8) | (addr[5]);
+
+ status =
+ ql_wait_reg_rdy(qdev,
+ MAC_ADDR_IDX, MAC_ADDR_MW, 0);
+ if (status)
+ goto exit;
+ ql_write32(qdev, MAC_ADDR_IDX, (offset++) |
+ (index << MAC_ADDR_IDX_SHIFT) |
+ type | MAC_ADDR_E);
+ ql_write32(qdev, MAC_ADDR_DATA, lower);
+ status =
+ ql_wait_reg_rdy(qdev,
+ MAC_ADDR_IDX, MAC_ADDR_MW, 0);
+ if (status)
+ goto exit;
+ ql_write32(qdev, MAC_ADDR_IDX, (offset++) |
+ (index << MAC_ADDR_IDX_SHIFT) |
+ type | MAC_ADDR_E);
+
+ ql_write32(qdev, MAC_ADDR_DATA, upper);
+ status =
+ ql_wait_reg_rdy(qdev,
+ MAC_ADDR_IDX, MAC_ADDR_MW, 0);
+ if (status)
+ goto exit;
+ break;
+ }
case MAC_ADDR_TYPE_CAM_MAC:
{
u32 cam_output;
@@ -366,16 +396,14 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
and possibly the function id. Right now we hardcode
the route field to NIC core.
*/
- if (type == MAC_ADDR_TYPE_CAM_MAC) {
- cam_output = (CAM_OUT_ROUTE_NIC |
- (qdev->
- func << CAM_OUT_FUNC_SHIFT) |
- (0 << CAM_OUT_CQ_ID_SHIFT));
- if (qdev->vlgrp)
- cam_output |= CAM_OUT_RV;
- /* route to NIC core */
- ql_write32(qdev, MAC_ADDR_DATA, cam_output);
- }
+ cam_output = (CAM_OUT_ROUTE_NIC |
+ (qdev->
+ func << CAM_OUT_FUNC_SHIFT) |
+ (0 << CAM_OUT_CQ_ID_SHIFT));
+ if (qdev->vlgrp)
+ cam_output |= CAM_OUT_RV;
+ /* route to NIC core */
+ ql_write32(qdev, MAC_ADDR_DATA, cam_output);
break;
}
case MAC_ADDR_TYPE_VLAN:
@@ -547,14 +575,14 @@ static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
}
case RT_IDX_MCAST: /* Pass up All Multicast frames. */
{
- value = RT_IDX_DST_CAM_Q | /* dest */
+ value = RT_IDX_DST_DFLT_Q | /* dest */
RT_IDX_TYPE_NICQ | /* type */
(RT_IDX_ALLMULTI_SLOT << RT_IDX_IDX_SHIFT);/* index */
break;
}
case RT_IDX_MCAST_MATCH: /* Pass up matched Multicast frames. */
{
- value = RT_IDX_DST_CAM_Q | /* dest */
+ value = RT_IDX_DST_DFLT_Q | /* dest */
RT_IDX_TYPE_NICQ | /* type */
(RT_IDX_MCAST_MATCH_SLOT << RT_IDX_IDX_SHIFT);/* index */
break;
@@ -1119,7 +1147,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");
@@ -1129,8 +1157,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;
@@ -1140,7 +1168,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);
}
@@ -1645,8 +1673,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 &&
@@ -1670,6 +1698,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;
@@ -1677,8 +1706,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;
@@ -1926,12 +1955,10 @@ static void ql_vlan_rx_add_vid(struct net_device *ndev, u16 vid)
status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
if (status)
return;
- spin_lock(&qdev->hw_lock);
if (ql_set_mac_addr_reg
(qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
QPRINTK(qdev, IFUP, ERR, "Failed to init vlan address.\n");
}
- spin_unlock(&qdev->hw_lock);
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
}
@@ -1945,12 +1972,10 @@ static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
if (status)
return;
- spin_lock(&qdev->hw_lock);
if (ql_set_mac_addr_reg
(qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
QPRINTK(qdev, IFUP, ERR, "Failed to clear vlan address.\n");
}
- spin_unlock(&qdev->hw_lock);
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
}
@@ -2001,15 +2026,17 @@ static irqreturn_t qlge_isr(int irq, void *dev_id)
/*
* Check MPI processor activity.
*/
- if (var & STS_PI) {
+ if ((var & STS_PI) &&
+ (ql_read32(qdev, INTR_MASK) & INTR_MASK_PI)) {
/*
* We've got an async event or mailbox completion.
* Handle it and clear the source of the interrupt.
*/
QPRINTK(qdev, INTR, ERR, "Got MPI processor interrupt.\n");
ql_disable_completion_interrupt(qdev, intr_context->intr);
- queue_delayed_work_on(smp_processor_id(), qdev->workqueue,
- &qdev->mpi_work, 0);
+ ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
+ queue_delayed_work_on(smp_processor_id(),
+ qdev->workqueue, &qdev->mpi_work, 0);
work_done++;
}
@@ -2666,7 +2693,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);
@@ -3080,6 +3107,12 @@ err_irq:
static int ql_start_rss(struct ql_adapter *qdev)
{
+ u8 init_hash_seed[] = {0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2,
+ 0x41, 0x67, 0x25, 0x3d, 0x43, 0xa3, 0x8f,
+ 0xb0, 0xd0, 0xca, 0x2b, 0xcb, 0xae, 0x7b,
+ 0x30, 0xb4, 0x77, 0xcb, 0x2d, 0xa3, 0x80,
+ 0x30, 0xf2, 0x0c, 0x6a, 0x42, 0xb7, 0x3b,
+ 0xbe, 0xac, 0x01, 0xfa};
struct ricb *ricb = &qdev->ricb;
int status = 0;
int i;
@@ -3089,21 +3122,17 @@ static int ql_start_rss(struct ql_adapter *qdev)
ricb->base_cq = RSS_L4K;
ricb->flags =
- (RSS_L6K | RSS_LI | RSS_LB | RSS_LM | RSS_RI4 | RSS_RI6 | RSS_RT4 |
- RSS_RT6);
- ricb->mask = cpu_to_le16(qdev->rss_ring_count - 1);
+ (RSS_L6K | RSS_LI | RSS_LB | RSS_LM | RSS_RT4 | RSS_RT6);
+ ricb->mask = cpu_to_le16((u16)(0x3ff));
/*
* Fill out the Indirection Table.
*/
- for (i = 0; i < 256; i++)
- hash_id[i] = i & (qdev->rss_ring_count - 1);
+ for (i = 0; i < 1024; i++)
+ hash_id[i] = (i & (qdev->rss_ring_count - 1));
- /*
- * Random values for the IPv6 and IPv4 Hash Keys.
- */
- get_random_bytes((void *)&ricb->ipv6_hash_key[0], 40);
- get_random_bytes((void *)&ricb->ipv4_hash_key[0], 16);
+ memcpy((void *)&ricb->ipv6_hash_key[0], init_hash_seed, 40);
+ memcpy((void *)&ricb->ipv4_hash_key[0], init_hash_seed, 16);
QPRINTK(qdev, IFUP, DEBUG, "Initializing RSS.\n");
@@ -3240,7 +3269,14 @@ 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.
+ * This is helpful on bonding where both interfaces can have
+ * the same MAC address.
+ */
+ ql_write32(qdev, RST_FO, RST_FO_RR_MASK | RST_FO_RR_RCV_FUNC_CQ);
/* Start up the rx queues. */
for (i = 0; i < qdev->rx_ring_count; i++) {
@@ -3275,10 +3311,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);
@@ -3314,6 +3348,13 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
end_jiffies = jiffies +
max((unsigned long)1, usecs_to_jiffies(30));
+
+ /* Stop management traffic. */
+ ql_mb_set_mgmnt_traffic_ctl(qdev, MB_SET_MPI_TFK_STOP);
+
+ /* Wait for the NIC and MGMNT FIFOs to empty. */
+ ql_wait_fifo_empty(qdev);
+
ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR);
do {
@@ -3329,6 +3370,8 @@ static int ql_adapter_reset(struct ql_adapter *qdev)
status = -ETIMEDOUT;
}
+ /* Resume management traffic. */
+ ql_mb_set_mgmnt_traffic_ctl(qdev, MB_SET_MPI_TFK_RESUME);
return status;
}
@@ -3504,7 +3547,7 @@ static int ql_configure_rings(struct ql_adapter *qdev)
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 {
/*
@@ -3572,8 +3615,7 @@ static int qlge_change_mtu(struct net_device *ndev, int new_mtu)
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)
@@ -3585,7 +3627,6 @@ static void qlge_set_multicast_list(struct net_device *ndev)
status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
if (status)
return;
- spin_lock(&qdev->hw_lock);
/*
* Set or clear promiscuous mode if a
* transition is taking place.
@@ -3662,7 +3703,6 @@ static void qlge_set_multicast_list(struct net_device *ndev)
}
}
exit:
- spin_unlock(&qdev->hw_lock);
ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
}
@@ -3682,10 +3722,8 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p)
status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
if (status)
return status;
- spin_lock(&qdev->hw_lock);
status = ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr,
MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
- spin_unlock(&qdev->hw_lock);
if (status)
QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n");
ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
@@ -3711,6 +3749,12 @@ static void ql_asic_reset_work(struct work_struct *work)
status = ql_adapter_up(qdev);
if (status)
goto error;
+
+ /* Restore rx mode. */
+ clear_bit(QL_ALLMULTI, &qdev->flags);
+ clear_bit(QL_PROMISCUOUS, &qdev->flags);
+ qlge_set_multicast_list(qdev->ndev);
+
rtnl_unlock();
return;
error:
@@ -3822,8 +3866,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);
@@ -3835,18 +3878,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);
@@ -3928,7 +3965,6 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work);
INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work);
INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
- mutex_init(&qdev->mpi_mutex);
init_completion(&qdev->ide_completion);
if (!cards_found) {
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 6685bd97da91..e497eac5eb45 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]);
@@ -472,7 +456,6 @@ static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp)
{
int status, count;
- mutex_lock(&qdev->mpi_mutex);
/* Begin polled mode for MPI */
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
@@ -537,11 +520,9 @@ 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:
- mutex_unlock(&qdev->mpi_mutex);
/* End polled mode for MPI */
ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
return status;
@@ -770,13 +751,104 @@ static int ql_idc_wait(struct ql_adapter *qdev)
return status;
}
+int ql_mb_set_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 control)
+{
+ 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_SET_MGMNT_TFK_CTL;
+ mbcp->mbox_in[1] = control;
+
+ status = ql_mailbox_command(qdev, mbcp);
+ if (status)
+ return status;
+
+ if (mbcp->mbox_out[0] == MB_CMD_STS_GOOD)
+ return status;
+
+ if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) {
+ QPRINTK(qdev, DRV, ERR,
+ "Command not supported by firmware.\n");
+ status = -EINVAL;
+ } else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) {
+ /* This indicates that the firmware is
+ * already in the state we are trying to
+ * change it to.
+ */
+ QPRINTK(qdev, DRV, ERR,
+ "Command parameters make no change.\n");
+ }
+ return status;
+}
+
+/* Returns a negative error code or the mailbox command status. */
+static int ql_mb_get_mgmnt_traffic_ctl(struct ql_adapter *qdev, u32 *control)
+{
+ struct mbox_params mbc;
+ struct mbox_params *mbcp = &mbc;
+ int status;
+
+ memset(mbcp, 0, sizeof(struct mbox_params));
+ *control = 0;
+
+ mbcp->in_count = 1;
+ mbcp->out_count = 1;
+
+ mbcp->mbox_in[0] = MB_CMD_GET_MGMNT_TFK_CTL;
+
+ status = ql_mailbox_command(qdev, mbcp);
+ if (status)
+ return status;
+
+ if (mbcp->mbox_out[0] == MB_CMD_STS_GOOD) {
+ *control = mbcp->mbox_in[1];
+ return status;
+ }
+
+ if (mbcp->mbox_out[0] == MB_CMD_STS_INVLD_CMD) {
+ QPRINTK(qdev, DRV, ERR,
+ "Command not supported by firmware.\n");
+ status = -EINVAL;
+ } else if (mbcp->mbox_out[0] == MB_CMD_STS_ERR) {
+ QPRINTK(qdev, DRV, ERR,
+ "Failed to get MPI traffic control.\n");
+ status = -EIO;
+ }
+ return status;
+}
+
+int ql_wait_fifo_empty(struct ql_adapter *qdev)
+{
+ int count = 5;
+ u32 mgmnt_fifo_empty;
+ u32 nic_fifo_empty;
+
+ do {
+ nic_fifo_empty = ql_read32(qdev, STS) & STS_NFE;
+ ql_mb_get_mgmnt_traffic_ctl(qdev, &mgmnt_fifo_empty);
+ mgmnt_fifo_empty &= MB_GET_MPI_TFK_FIFO_EMPTY;
+ if (nic_fifo_empty && mgmnt_fifo_empty)
+ return 0;
+ msleep(100);
+ } while (count-- > 0);
+ return -ETIMEDOUT;
+}
+
/* API called in work thread context to set new TX/RX
* maximum frame size values to match MTU.
*/
static int ql_set_port_cfg(struct ql_adapter *qdev)
{
int status;
+ rtnl_lock();
status = ql_mb_set_port_cfg(qdev);
+ rtnl_unlock();
if (status)
return status;
status = ql_idc_wait(qdev);
@@ -797,7 +869,9 @@ void ql_mpi_port_cfg_work(struct work_struct *work)
container_of(work, struct ql_adapter, mpi_port_cfg_work.work);
int status;
+ rtnl_lock();
status = ql_mb_get_port_cfg(qdev);
+ rtnl_unlock();
if (status) {
QPRINTK(qdev, DRV, ERR,
"Bug: Failed to get port config data.\n");
@@ -855,7 +929,9 @@ void ql_mpi_idc_work(struct work_struct *work)
* needs to be set.
* */
set_bit(QL_CAM_RT_SET, &qdev->flags);
+ rtnl_lock();
status = ql_mb_idc_ack(qdev);
+ rtnl_unlock();
if (status) {
QPRINTK(qdev, DRV, ERR,
"Bug: No pending IDC!\n");
@@ -871,7 +947,9 @@ void ql_mpi_work(struct work_struct *work)
struct mbox_params *mbcp = &mbc;
int err = 0;
- mutex_lock(&qdev->mpi_mutex);
+ rtnl_lock();
+ /* Begin polled mode for MPI */
+ ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
while (ql_read32(qdev, STS) & STS_PI) {
memset(mbcp, 0, sizeof(struct mbox_params));
@@ -884,7 +962,9 @@ void ql_mpi_work(struct work_struct *work)
break;
}
- mutex_unlock(&qdev->mpi_mutex);
+ /* End polled mode for MPI */
+ ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
+ rtnl_unlock();
ql_enable_completion_interrupt(qdev, 0);
}
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 50c6a3cfe439..7d9fc06ceb98 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -115,7 +115,9 @@ enum mac_version {
RTL_GIGA_MAC_VER_22 = 0x16, // 8168C
RTL_GIGA_MAC_VER_23 = 0x17, // 8168CP
RTL_GIGA_MAC_VER_24 = 0x18, // 8168CP
- RTL_GIGA_MAC_VER_25 = 0x19 // 8168D
+ RTL_GIGA_MAC_VER_25 = 0x19, // 8168D
+ RTL_GIGA_MAC_VER_26 = 0x1a, // 8168D
+ RTL_GIGA_MAC_VER_27 = 0x1b // 8168DP
};
#define _R(NAME,MAC,MASK) \
@@ -150,7 +152,9 @@ static const struct {
_R("RTL8168c/8111c", RTL_GIGA_MAC_VER_22, 0xff7e1880), // PCI-E
_R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_23, 0xff7e1880), // PCI-E
_R("RTL8168cp/8111cp", RTL_GIGA_MAC_VER_24, 0xff7e1880), // PCI-E
- _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880) // PCI-E
+ _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_25, 0xff7e1880), // PCI-E
+ _R("RTL8168d/8111d", RTL_GIGA_MAC_VER_26, 0xff7e1880), // PCI-E
+ _R("RTL8168dp/8111dp", RTL_GIGA_MAC_VER_27, 0xff7e1880) // PCI-E
};
#undef _R
@@ -253,6 +257,13 @@ enum rtl8168_8101_registers {
DBG_REG = 0xd1,
#define FIX_NAK_1 (1 << 4)
#define FIX_NAK_2 (1 << 3)
+ EFUSEAR = 0xdc,
+#define EFUSEAR_FLAG 0x80000000
+#define EFUSEAR_WRITE_CMD 0x80000000
+#define EFUSEAR_READ_CMD 0x00000000
+#define EFUSEAR_REG_MASK 0x03ff
+#define EFUSEAR_REG_SHIFT 8
+#define EFUSEAR_DATA_MASK 0xff
};
enum rtl_register_content {
@@ -568,6 +579,14 @@ static void mdio_patch(void __iomem *ioaddr, int reg_addr, int value)
mdio_write(ioaddr, reg_addr, mdio_read(ioaddr, reg_addr) | value);
}
+static void mdio_plus_minus(void __iomem *ioaddr, int reg_addr, int p, int m)
+{
+ int val;
+
+ val = mdio_read(ioaddr, reg_addr);
+ mdio_write(ioaddr, reg_addr, (val | p) & ~m);
+}
+
static void rtl_mdio_write(struct net_device *dev, int phy_id, int location,
int val)
{
@@ -651,6 +670,24 @@ static u32 rtl_csi_read(void __iomem *ioaddr, int addr)
return value;
}
+static u8 rtl8168d_efuse_read(void __iomem *ioaddr, int reg_addr)
+{
+ u8 value = 0xff;
+ unsigned int i;
+
+ RTL_W32(EFUSEAR, (reg_addr & EFUSEAR_REG_MASK) << EFUSEAR_REG_SHIFT);
+
+ for (i = 0; i < 300; i++) {
+ if (RTL_R32(EFUSEAR) & EFUSEAR_FLAG) {
+ value = RTL_R32(EFUSEAR) & EFUSEAR_DATA_MASK;
+ break;
+ }
+ udelay(100);
+ }
+
+ return value;
+}
+
static void rtl8169_irq_mask_and_ack(void __iomem *ioaddr)
{
RTL_W16(IntrMask, 0x0000);
@@ -1243,7 +1280,10 @@ static void rtl8169_get_mac_version(struct rtl8169_private *tp,
int mac_version;
} mac_info[] = {
/* 8168D family. */
- { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_25 },
+ { 0x7cf00000, 0x28300000, RTL_GIGA_MAC_VER_26 },
+ { 0x7cf00000, 0x28100000, RTL_GIGA_MAC_VER_25 },
+ { 0x7c800000, 0x28800000, RTL_GIGA_MAC_VER_27 },
+ { 0x7c800000, 0x28000000, RTL_GIGA_MAC_VER_26 },
/* 8168C family. */
{ 0x7cf00000, 0x3ca00000, RTL_GIGA_MAC_VER_24 },
@@ -1648,74 +1688,903 @@ static void rtl8168c_4_hw_phy_config(void __iomem *ioaddr)
rtl8168c_3_hw_phy_config(ioaddr);
}
-static void rtl8168d_hw_phy_config(void __iomem *ioaddr)
+static void rtl8168d_1_hw_phy_config(void __iomem *ioaddr)
{
- struct phy_reg phy_reg_init_0[] = {
+ static struct phy_reg phy_reg_init_0[] = {
{ 0x1f, 0x0001 },
- { 0x09, 0x2770 },
- { 0x08, 0x04d0 },
- { 0x0b, 0xad15 },
- { 0x0c, 0x5bf0 },
- { 0x1c, 0xf101 },
+ { 0x06, 0x4064 },
+ { 0x07, 0x2863 },
+ { 0x08, 0x059c },
+ { 0x09, 0x26b4 },
+ { 0x0a, 0x6a19 },
+ { 0x0b, 0xdcc8 },
+ { 0x10, 0xf06d },
+ { 0x14, 0x7f68 },
+ { 0x18, 0x7fd9 },
+ { 0x1c, 0xf0ff },
+ { 0x1d, 0x3d9c },
{ 0x1f, 0x0003 },
- { 0x14, 0x94d7 },
- { 0x12, 0xf4d6 },
- { 0x09, 0xca0f },
- { 0x1f, 0x0002 },
- { 0x0b, 0x0b10 },
- { 0x0c, 0xd1f7 },
- { 0x1f, 0x0002 },
- { 0x06, 0x5461 },
+ { 0x12, 0xf49f },
+ { 0x13, 0x070b },
+ { 0x1a, 0x05ad },
+ { 0x14, 0x94c0 }
+ };
+ static struct phy_reg phy_reg_init_1[] = {
{ 0x1f, 0x0002 },
- { 0x05, 0x6662 },
+ { 0x06, 0x5561 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8332 },
+ { 0x06, 0x5561 }
+ };
+ static struct phy_reg phy_reg_init_2[] = {
+ { 0x1f, 0x0005 },
+ { 0x05, 0xffc2 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8000 },
+ { 0x06, 0xf8f9 },
+ { 0x06, 0xfaef },
+ { 0x06, 0x59ee },
+ { 0x06, 0xf8ea },
+ { 0x06, 0x00ee },
+ { 0x06, 0xf8eb },
+ { 0x06, 0x00e0 },
+ { 0x06, 0xf87c },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x7d59 },
+ { 0x06, 0x0fef },
+ { 0x06, 0x0139 },
+ { 0x06, 0x029e },
+ { 0x06, 0x06ef },
+ { 0x06, 0x1039 },
+ { 0x06, 0x089f },
+ { 0x06, 0x2aee },
+ { 0x06, 0xf8ea },
+ { 0x06, 0x00ee },
+ { 0x06, 0xf8eb },
+ { 0x06, 0x01e0 },
+ { 0x06, 0xf87c },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x7d58 },
+ { 0x06, 0x409e },
+ { 0x06, 0x0f39 },
+ { 0x06, 0x46aa },
+ { 0x06, 0x0bbf },
+ { 0x06, 0x8290 },
+ { 0x06, 0xd682 },
+ { 0x06, 0x9802 },
+ { 0x06, 0x014f },
+ { 0x06, 0xae09 },
+ { 0x06, 0xbf82 },
+ { 0x06, 0x98d6 },
+ { 0x06, 0x82a0 },
+ { 0x06, 0x0201 },
+ { 0x06, 0x4fef },
+ { 0x06, 0x95fe },
+ { 0x06, 0xfdfc },
+ { 0x06, 0x05f8 },
+ { 0x06, 0xf9fa },
+ { 0x06, 0xeef8 },
+ { 0x06, 0xea00 },
+ { 0x06, 0xeef8 },
+ { 0x06, 0xeb00 },
+ { 0x06, 0xe2f8 },
+ { 0x06, 0x7ce3 },
+ { 0x06, 0xf87d },
+ { 0x06, 0xa511 },
+ { 0x06, 0x1112 },
+ { 0x06, 0xd240 },
+ { 0x06, 0xd644 },
+ { 0x06, 0x4402 },
+ { 0x06, 0x8217 },
+ { 0x06, 0xd2a0 },
+ { 0x06, 0xd6aa },
+ { 0x06, 0xaa02 },
+ { 0x06, 0x8217 },
+ { 0x06, 0xae0f },
+ { 0x06, 0xa544 },
+ { 0x06, 0x4402 },
+ { 0x06, 0xae4d },
+ { 0x06, 0xa5aa },
+ { 0x06, 0xaa02 },
+ { 0x06, 0xae47 },
+ { 0x06, 0xaf82 },
+ { 0x06, 0x13ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x00ee },
+ { 0x06, 0x834d },
+ { 0x06, 0x0fee },
+ { 0x06, 0x834c },
+ { 0x06, 0x0fee },
+ { 0x06, 0x834f },
+ { 0x06, 0x00ee },
+ { 0x06, 0x8351 },
+ { 0x06, 0x00ee },
+ { 0x06, 0x834a },
+ { 0x06, 0xffee },
+ { 0x06, 0x834b },
+ { 0x06, 0xffe0 },
+ { 0x06, 0x8330 },
+ { 0x06, 0xe183 },
+ { 0x06, 0x3158 },
+ { 0x06, 0xfee4 },
+ { 0x06, 0xf88a },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x8be0 },
+ { 0x06, 0x8332 },
+ { 0x06, 0xe183 },
+ { 0x06, 0x3359 },
+ { 0x06, 0x0fe2 },
+ { 0x06, 0x834d },
+ { 0x06, 0x0c24 },
+ { 0x06, 0x5af0 },
+ { 0x06, 0x1e12 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x8ce5 },
+ { 0x06, 0xf88d },
+ { 0x06, 0xaf82 },
+ { 0x06, 0x13e0 },
+ { 0x06, 0x834f },
+ { 0x06, 0x10e4 },
+ { 0x06, 0x834f },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x009f },
+ { 0x06, 0x0ae0 },
+ { 0x06, 0x834f },
+ { 0x06, 0xa010 },
+ { 0x06, 0xa5ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x01e0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7805 },
+ { 0x06, 0x9e9a },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x049e },
+ { 0x06, 0x10e0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7803 },
+ { 0x06, 0x9e0f },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x019e },
+ { 0x06, 0x05ae },
+ { 0x06, 0x0caf },
+ { 0x06, 0x81f8 },
+ { 0x06, 0xaf81 },
+ { 0x06, 0xa3af },
+ { 0x06, 0x81dc },
+ { 0x06, 0xaf82 },
+ { 0x06, 0x13ee },
+ { 0x06, 0x8348 },
+ { 0x06, 0x00ee },
+ { 0x06, 0x8349 },
+ { 0x06, 0x00e0 },
+ { 0x06, 0x8351 },
+ { 0x06, 0x10e4 },
+ { 0x06, 0x8351 },
+ { 0x06, 0x5801 },
+ { 0x06, 0x9fea },
+ { 0x06, 0xd000 },
+ { 0x06, 0xd180 },
+ { 0x06, 0x1f66 },
+ { 0x06, 0xe2f8 },
+ { 0x06, 0xeae3 },
+ { 0x06, 0xf8eb },
+ { 0x06, 0x5af8 },
+ { 0x06, 0x1e20 },
+ { 0x06, 0xe6f8 },
+ { 0x06, 0xeae5 },
+ { 0x06, 0xf8eb },
+ { 0x06, 0xd302 },
+ { 0x06, 0xb3fe },
+ { 0x06, 0xe2f8 },
+ { 0x06, 0x7cef },
+ { 0x06, 0x325b },
+ { 0x06, 0x80e3 },
+ { 0x06, 0xf87d },
+ { 0x06, 0x9e03 },
+ { 0x06, 0x7dff },
+ { 0x06, 0xff0d },
+ { 0x06, 0x581c },
+ { 0x06, 0x551a },
+ { 0x06, 0x6511 },
+ { 0x06, 0xa190 },
+ { 0x06, 0xd3e2 },
+ { 0x06, 0x8348 },
+ { 0x06, 0xe383 },
+ { 0x06, 0x491b },
+ { 0x06, 0x56ab },
+ { 0x06, 0x08ef },
+ { 0x06, 0x56e6 },
+ { 0x06, 0x8348 },
+ { 0x06, 0xe783 },
+ { 0x06, 0x4910 },
+ { 0x06, 0xd180 },
+ { 0x06, 0x1f66 },
+ { 0x06, 0xa004 },
+ { 0x06, 0xb9e2 },
+ { 0x06, 0x8348 },
+ { 0x06, 0xe383 },
+ { 0x06, 0x49ef },
+ { 0x06, 0x65e2 },
+ { 0x06, 0x834a },
+ { 0x06, 0xe383 },
+ { 0x06, 0x4b1b },
+ { 0x06, 0x56aa },
+ { 0x06, 0x0eef },
+ { 0x06, 0x56e6 },
+ { 0x06, 0x834a },
+ { 0x06, 0xe783 },
+ { 0x06, 0x4be2 },
+ { 0x06, 0x834d },
+ { 0x06, 0xe683 },
+ { 0x06, 0x4ce0 },
+ { 0x06, 0x834d },
+ { 0x06, 0xa000 },
+ { 0x06, 0x0caf },
+ { 0x06, 0x81dc },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4d10 },
+ { 0x06, 0xe483 },
+ { 0x06, 0x4dae },
+ { 0x06, 0x0480 },
+ { 0x06, 0xe483 },
+ { 0x06, 0x4de0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7803 },
+ { 0x06, 0x9e0b },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x049e },
+ { 0x06, 0x04ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x02e0 },
+ { 0x06, 0x8332 },
+ { 0x06, 0xe183 },
+ { 0x06, 0x3359 },
+ { 0x06, 0x0fe2 },
+ { 0x06, 0x834d },
+ { 0x06, 0x0c24 },
+ { 0x06, 0x5af0 },
+ { 0x06, 0x1e12 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x8ce5 },
+ { 0x06, 0xf88d },
+ { 0x06, 0xe083 },
+ { 0x06, 0x30e1 },
+ { 0x06, 0x8331 },
+ { 0x06, 0x6801 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x8ae5 },
+ { 0x06, 0xf88b },
+ { 0x06, 0xae37 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e03 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4ce1 },
+ { 0x06, 0x834d },
+ { 0x06, 0x1b01 },
+ { 0x06, 0x9e04 },
+ { 0x06, 0xaaa1 },
+ { 0x06, 0xaea8 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e04 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4f00 },
+ { 0x06, 0xaeab },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4f78 },
+ { 0x06, 0x039f },
+ { 0x06, 0x14ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x05d2 },
+ { 0x06, 0x40d6 },
+ { 0x06, 0x5554 },
+ { 0x06, 0x0282 },
+ { 0x06, 0x17d2 },
+ { 0x06, 0xa0d6 },
+ { 0x06, 0xba00 },
+ { 0x06, 0x0282 },
+ { 0x06, 0x17fe },
+ { 0x06, 0xfdfc },
+ { 0x06, 0x05f8 },
+ { 0x06, 0xe0f8 },
+ { 0x06, 0x60e1 },
+ { 0x06, 0xf861 },
+ { 0x06, 0x6802 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x60e5 },
+ { 0x06, 0xf861 },
+ { 0x06, 0xe0f8 },
+ { 0x06, 0x48e1 },
+ { 0x06, 0xf849 },
+ { 0x06, 0x580f },
+ { 0x06, 0x1e02 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x48e5 },
+ { 0x06, 0xf849 },
+ { 0x06, 0xd000 },
+ { 0x06, 0x0282 },
+ { 0x06, 0x5bbf },
+ { 0x06, 0x8350 },
+ { 0x06, 0xef46 },
+ { 0x06, 0xdc19 },
+ { 0x06, 0xddd0 },
+ { 0x06, 0x0102 },
+ { 0x06, 0x825b },
+ { 0x06, 0x0282 },
+ { 0x06, 0x77e0 },
+ { 0x06, 0xf860 },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x6158 },
+ { 0x06, 0xfde4 },
+ { 0x06, 0xf860 },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x61fc },
+ { 0x06, 0x04f9 },
+ { 0x06, 0xfafb },
+ { 0x06, 0xc6bf },
+ { 0x06, 0xf840 },
+ { 0x06, 0xbe83 },
+ { 0x06, 0x50a0 },
+ { 0x06, 0x0101 },
+ { 0x06, 0x071b },
+ { 0x06, 0x89cf },
+ { 0x06, 0xd208 },
+ { 0x06, 0xebdb },
+ { 0x06, 0x19b2 },
+ { 0x06, 0xfbff },
+ { 0x06, 0xfefd },
+ { 0x06, 0x04f8 },
+ { 0x06, 0xe0f8 },
+ { 0x06, 0x48e1 },
+ { 0x06, 0xf849 },
+ { 0x06, 0x6808 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x48e5 },
+ { 0x06, 0xf849 },
+ { 0x06, 0x58f7 },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x48e5 },
+ { 0x06, 0xf849 },
+ { 0x06, 0xfc04 },
+ { 0x06, 0x4d20 },
+ { 0x06, 0x0002 },
+ { 0x06, 0x4e22 },
+ { 0x06, 0x0002 },
+ { 0x06, 0x4ddf },
+ { 0x06, 0xff01 },
+ { 0x06, 0x4edd },
+ { 0x06, 0xff01 },
+ { 0x05, 0x83d4 },
+ { 0x06, 0x8000 },
+ { 0x05, 0x83d8 },
+ { 0x06, 0x8051 },
+ { 0x02, 0x6010 },
+ { 0x03, 0xdc00 },
+ { 0x05, 0xfff6 },
+ { 0x06, 0x00fc },
{ 0x1f, 0x0000 },
- { 0x14, 0x0060 },
+
{ 0x1f, 0x0000 },
- { 0x0d, 0xf8a0 },
+ { 0x0d, 0xf880 },
+ { 0x1f, 0x0000 }
+ };
+
+ rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
+
+ mdio_write(ioaddr, 0x1f, 0x0002);
+ mdio_plus_minus(ioaddr, 0x0b, 0x0010, 0x00ef);
+ mdio_plus_minus(ioaddr, 0x0c, 0xa200, 0x5d00);
+
+ rtl_phy_write(ioaddr, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1));
+
+ if (rtl8168d_efuse_read(ioaddr, 0x01) == 0xb1) {
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0002 },
+ { 0x05, 0x669a },
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8330 },
+ { 0x06, 0x669a },
+ { 0x1f, 0x0002 }
+ };
+ int val;
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ val = mdio_read(ioaddr, 0x0d);
+
+ if ((val & 0x00ff) != 0x006c) {
+ u32 set[] = {
+ 0x0065, 0x0066, 0x0067, 0x0068,
+ 0x0069, 0x006a, 0x006b, 0x006c
+ };
+ int i;
+
+ mdio_write(ioaddr, 0x1f, 0x0002);
+
+ val &= 0xff00;
+ for (i = 0; i < ARRAY_SIZE(set); i++)
+ mdio_write(ioaddr, 0x0d, val | set[i]);
+ }
+ } else {
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0002 },
+ { 0x05, 0x6662 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8330 },
+ { 0x06, 0x6662 }
+ };
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+ }
+
+ mdio_write(ioaddr, 0x1f, 0x0002);
+ mdio_patch(ioaddr, 0x0d, 0x0300);
+ mdio_patch(ioaddr, 0x0f, 0x0010);
+
+ mdio_write(ioaddr, 0x1f, 0x0002);
+ mdio_plus_minus(ioaddr, 0x02, 0x0100, 0x0600);
+ mdio_plus_minus(ioaddr, 0x03, 0x0000, 0xe000);
+
+ rtl_phy_write(ioaddr, phy_reg_init_2, ARRAY_SIZE(phy_reg_init_2));
+}
+
+static void rtl8168d_2_hw_phy_config(void __iomem *ioaddr)
+{
+ static struct phy_reg phy_reg_init_0[] = {
+ { 0x1f, 0x0001 },
+ { 0x06, 0x4064 },
+ { 0x07, 0x2863 },
+ { 0x08, 0x059c },
+ { 0x09, 0x26b4 },
+ { 0x0a, 0x6a19 },
+ { 0x0b, 0xdcc8 },
+ { 0x10, 0xf06d },
+ { 0x14, 0x7f68 },
+ { 0x18, 0x7fd9 },
+ { 0x1c, 0xf0ff },
+ { 0x1d, 0x3d9c },
+ { 0x1f, 0x0003 },
+ { 0x12, 0xf49f },
+ { 0x13, 0x070b },
+ { 0x1a, 0x05ad },
+ { 0x14, 0x94c0 },
+
+ { 0x1f, 0x0002 },
+ { 0x06, 0x5561 },
+ { 0x1f, 0x0005 },
+ { 0x05, 0x8332 },
+ { 0x06, 0x5561 }
+ };
+ static struct phy_reg phy_reg_init_1[] = {
+ { 0x1f, 0x0005 },
+ { 0x05, 0xffc2 },
{ 0x1f, 0x0005 },
- { 0x05, 0xffc2 }
+ { 0x05, 0x8000 },
+ { 0x06, 0xf8f9 },
+ { 0x06, 0xfaee },
+ { 0x06, 0xf8ea },
+ { 0x06, 0x00ee },
+ { 0x06, 0xf8eb },
+ { 0x06, 0x00e2 },
+ { 0x06, 0xf87c },
+ { 0x06, 0xe3f8 },
+ { 0x06, 0x7da5 },
+ { 0x06, 0x1111 },
+ { 0x06, 0x12d2 },
+ { 0x06, 0x40d6 },
+ { 0x06, 0x4444 },
+ { 0x06, 0x0281 },
+ { 0x06, 0xc6d2 },
+ { 0x06, 0xa0d6 },
+ { 0x06, 0xaaaa },
+ { 0x06, 0x0281 },
+ { 0x06, 0xc6ae },
+ { 0x06, 0x0fa5 },
+ { 0x06, 0x4444 },
+ { 0x06, 0x02ae },
+ { 0x06, 0x4da5 },
+ { 0x06, 0xaaaa },
+ { 0x06, 0x02ae },
+ { 0x06, 0x47af },
+ { 0x06, 0x81c2 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e00 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4d0f },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4c0f },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4f00 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x5100 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4aff },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4bff },
+ { 0x06, 0xe083 },
+ { 0x06, 0x30e1 },
+ { 0x06, 0x8331 },
+ { 0x06, 0x58fe },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x8ae5 },
+ { 0x06, 0xf88b },
+ { 0x06, 0xe083 },
+ { 0x06, 0x32e1 },
+ { 0x06, 0x8333 },
+ { 0x06, 0x590f },
+ { 0x06, 0xe283 },
+ { 0x06, 0x4d0c },
+ { 0x06, 0x245a },
+ { 0x06, 0xf01e },
+ { 0x06, 0x12e4 },
+ { 0x06, 0xf88c },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x8daf },
+ { 0x06, 0x81c2 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4f10 },
+ { 0x06, 0xe483 },
+ { 0x06, 0x4fe0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7800 },
+ { 0x06, 0x9f0a },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4fa0 },
+ { 0x06, 0x10a5 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e01 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x059e },
+ { 0x06, 0x9ae0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7804 },
+ { 0x06, 0x9e10 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x039e },
+ { 0x06, 0x0fe0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7801 },
+ { 0x06, 0x9e05 },
+ { 0x06, 0xae0c },
+ { 0x06, 0xaf81 },
+ { 0x06, 0xa7af },
+ { 0x06, 0x8152 },
+ { 0x06, 0xaf81 },
+ { 0x06, 0x8baf },
+ { 0x06, 0x81c2 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4800 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4900 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x5110 },
+ { 0x06, 0xe483 },
+ { 0x06, 0x5158 },
+ { 0x06, 0x019f },
+ { 0x06, 0xead0 },
+ { 0x06, 0x00d1 },
+ { 0x06, 0x801f },
+ { 0x06, 0x66e2 },
+ { 0x06, 0xf8ea },
+ { 0x06, 0xe3f8 },
+ { 0x06, 0xeb5a },
+ { 0x06, 0xf81e },
+ { 0x06, 0x20e6 },
+ { 0x06, 0xf8ea },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0xebd3 },
+ { 0x06, 0x02b3 },
+ { 0x06, 0xfee2 },
+ { 0x06, 0xf87c },
+ { 0x06, 0xef32 },
+ { 0x06, 0x5b80 },
+ { 0x06, 0xe3f8 },
+ { 0x06, 0x7d9e },
+ { 0x06, 0x037d },
+ { 0x06, 0xffff },
+ { 0x06, 0x0d58 },
+ { 0x06, 0x1c55 },
+ { 0x06, 0x1a65 },
+ { 0x06, 0x11a1 },
+ { 0x06, 0x90d3 },
+ { 0x06, 0xe283 },
+ { 0x06, 0x48e3 },
+ { 0x06, 0x8349 },
+ { 0x06, 0x1b56 },
+ { 0x06, 0xab08 },
+ { 0x06, 0xef56 },
+ { 0x06, 0xe683 },
+ { 0x06, 0x48e7 },
+ { 0x06, 0x8349 },
+ { 0x06, 0x10d1 },
+ { 0x06, 0x801f },
+ { 0x06, 0x66a0 },
+ { 0x06, 0x04b9 },
+ { 0x06, 0xe283 },
+ { 0x06, 0x48e3 },
+ { 0x06, 0x8349 },
+ { 0x06, 0xef65 },
+ { 0x06, 0xe283 },
+ { 0x06, 0x4ae3 },
+ { 0x06, 0x834b },
+ { 0x06, 0x1b56 },
+ { 0x06, 0xaa0e },
+ { 0x06, 0xef56 },
+ { 0x06, 0xe683 },
+ { 0x06, 0x4ae7 },
+ { 0x06, 0x834b },
+ { 0x06, 0xe283 },
+ { 0x06, 0x4de6 },
+ { 0x06, 0x834c },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4da0 },
+ { 0x06, 0x000c },
+ { 0x06, 0xaf81 },
+ { 0x06, 0x8be0 },
+ { 0x06, 0x834d },
+ { 0x06, 0x10e4 },
+ { 0x06, 0x834d },
+ { 0x06, 0xae04 },
+ { 0x06, 0x80e4 },
+ { 0x06, 0x834d },
+ { 0x06, 0xe083 },
+ { 0x06, 0x4e78 },
+ { 0x06, 0x039e },
+ { 0x06, 0x0be0 },
+ { 0x06, 0x834e },
+ { 0x06, 0x7804 },
+ { 0x06, 0x9e04 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e02 },
+ { 0x06, 0xe083 },
+ { 0x06, 0x32e1 },
+ { 0x06, 0x8333 },
+ { 0x06, 0x590f },
+ { 0x06, 0xe283 },
+ { 0x06, 0x4d0c },
+ { 0x06, 0x245a },
+ { 0x06, 0xf01e },
+ { 0x06, 0x12e4 },
+ { 0x06, 0xf88c },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x8de0 },
+ { 0x06, 0x8330 },
+ { 0x06, 0xe183 },
+ { 0x06, 0x3168 },
+ { 0x06, 0x01e4 },
+ { 0x06, 0xf88a },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x8bae },
+ { 0x06, 0x37ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x03e0 },
+ { 0x06, 0x834c },
+ { 0x06, 0xe183 },
+ { 0x06, 0x4d1b },
+ { 0x06, 0x019e },
+ { 0x06, 0x04aa },
+ { 0x06, 0xa1ae },
+ { 0x06, 0xa8ee },
+ { 0x06, 0x834e },
+ { 0x06, 0x04ee },
+ { 0x06, 0x834f },
+ { 0x06, 0x00ae },
+ { 0x06, 0xabe0 },
+ { 0x06, 0x834f },
+ { 0x06, 0x7803 },
+ { 0x06, 0x9f14 },
+ { 0x06, 0xee83 },
+ { 0x06, 0x4e05 },
+ { 0x06, 0xd240 },
+ { 0x06, 0xd655 },
+ { 0x06, 0x5402 },
+ { 0x06, 0x81c6 },
+ { 0x06, 0xd2a0 },
+ { 0x06, 0xd6ba },
+ { 0x06, 0x0002 },
+ { 0x06, 0x81c6 },
+ { 0x06, 0xfefd },
+ { 0x06, 0xfc05 },
+ { 0x06, 0xf8e0 },
+ { 0x06, 0xf860 },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x6168 },
+ { 0x06, 0x02e4 },
+ { 0x06, 0xf860 },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x61e0 },
+ { 0x06, 0xf848 },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x4958 },
+ { 0x06, 0x0f1e },
+ { 0x06, 0x02e4 },
+ { 0x06, 0xf848 },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x49d0 },
+ { 0x06, 0x0002 },
+ { 0x06, 0x820a },
+ { 0x06, 0xbf83 },
+ { 0x06, 0x50ef },
+ { 0x06, 0x46dc },
+ { 0x06, 0x19dd },
+ { 0x06, 0xd001 },
+ { 0x06, 0x0282 },
+ { 0x06, 0x0a02 },
+ { 0x06, 0x8226 },
+ { 0x06, 0xe0f8 },
+ { 0x06, 0x60e1 },
+ { 0x06, 0xf861 },
+ { 0x06, 0x58fd },
+ { 0x06, 0xe4f8 },
+ { 0x06, 0x60e5 },
+ { 0x06, 0xf861 },
+ { 0x06, 0xfc04 },
+ { 0x06, 0xf9fa },
+ { 0x06, 0xfbc6 },
+ { 0x06, 0xbff8 },
+ { 0x06, 0x40be },
+ { 0x06, 0x8350 },
+ { 0x06, 0xa001 },
+ { 0x06, 0x0107 },
+ { 0x06, 0x1b89 },
+ { 0x06, 0xcfd2 },
+ { 0x06, 0x08eb },
+ { 0x06, 0xdb19 },
+ { 0x06, 0xb2fb },
+ { 0x06, 0xfffe },
+ { 0x06, 0xfd04 },
+ { 0x06, 0xf8e0 },
+ { 0x06, 0xf848 },
+ { 0x06, 0xe1f8 },
+ { 0x06, 0x4968 },
+ { 0x06, 0x08e4 },
+ { 0x06, 0xf848 },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x4958 },
+ { 0x06, 0xf7e4 },
+ { 0x06, 0xf848 },
+ { 0x06, 0xe5f8 },
+ { 0x06, 0x49fc },
+ { 0x06, 0x044d },
+ { 0x06, 0x2000 },
+ { 0x06, 0x024e },
+ { 0x06, 0x2200 },
+ { 0x06, 0x024d },
+ { 0x06, 0xdfff },
+ { 0x06, 0x014e },
+ { 0x06, 0xddff },
+ { 0x06, 0x0100 },
+ { 0x05, 0x83d8 },
+ { 0x06, 0x8000 },
+ { 0x03, 0xdc00 },
+ { 0x05, 0xfff6 },
+ { 0x06, 0x00fc },
+ { 0x1f, 0x0000 },
+
+ { 0x1f, 0x0000 },
+ { 0x0d, 0xf880 },
+ { 0x1f, 0x0000 }
};
rtl_phy_write(ioaddr, phy_reg_init_0, ARRAY_SIZE(phy_reg_init_0));
- if (mdio_read(ioaddr, 0x06) == 0xc400) {
- struct phy_reg phy_reg_init_1[] = {
+ if (rtl8168d_efuse_read(ioaddr, 0x01) == 0xb1) {
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0002 },
+ { 0x05, 0x669a },
{ 0x1f, 0x0005 },
- { 0x01, 0x0300 },
- { 0x1f, 0x0000 },
- { 0x11, 0x401c },
- { 0x16, 0x4100 },
+ { 0x05, 0x8330 },
+ { 0x06, 0x669a },
+
+ { 0x1f, 0x0002 }
+ };
+ int val;
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
+
+ val = mdio_read(ioaddr, 0x0d);
+ if ((val & 0x00ff) != 0x006c) {
+ u32 set[] = {
+ 0x0065, 0x0066, 0x0067, 0x0068,
+ 0x0069, 0x006a, 0x006b, 0x006c
+ };
+ int i;
+
+ mdio_write(ioaddr, 0x1f, 0x0002);
+
+ val &= 0xff00;
+ for (i = 0; i < ARRAY_SIZE(set); i++)
+ mdio_write(ioaddr, 0x0d, val | set[i]);
+ }
+ } else {
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0002 },
+ { 0x05, 0x2642 },
{ 0x1f, 0x0005 },
- { 0x07, 0x0010 },
- { 0x05, 0x83dc },
- { 0x06, 0x087d },
- { 0x05, 0x8300 },
- { 0x06, 0x0101 },
- { 0x06, 0x05f8 },
- { 0x06, 0xf9fa },
- { 0x06, 0xfbef },
- { 0x06, 0x79e2 },
- { 0x06, 0x835f },
- { 0x06, 0xe0f8 },
- { 0x06, 0x9ae1 },
- { 0x06, 0xf89b },
- { 0x06, 0xef31 },
- { 0x06, 0x3b65 },
- { 0x06, 0xaa07 },
- { 0x06, 0x81e4 },
- { 0x06, 0xf89a },
- { 0x06, 0xe5f8 },
- { 0x06, 0x9baf },
- { 0x06, 0x06ae },
- { 0x05, 0x83dc },
- { 0x06, 0x8300 },
+ { 0x05, 0x8330 },
+ { 0x06, 0x2642 }
};
- rtl_phy_write(ioaddr, phy_reg_init_1,
- ARRAY_SIZE(phy_reg_init_1));
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
- mdio_write(ioaddr, 0x1f, 0x0000);
+ mdio_write(ioaddr, 0x1f, 0x0002);
+ mdio_plus_minus(ioaddr, 0x02, 0x0100, 0x0600);
+ mdio_plus_minus(ioaddr, 0x03, 0x0000, 0xe000);
+
+ mdio_write(ioaddr, 0x1f, 0x0001);
+ mdio_write(ioaddr, 0x17, 0x0cc0);
+
+ mdio_write(ioaddr, 0x1f, 0x0002);
+ mdio_patch(ioaddr, 0x0f, 0x0017);
+
+ rtl_phy_write(ioaddr, phy_reg_init_1, ARRAY_SIZE(phy_reg_init_1));
+}
+
+static void rtl8168d_3_hw_phy_config(void __iomem *ioaddr)
+{
+ struct phy_reg phy_reg_init[] = {
+ { 0x1f, 0x0002 },
+ { 0x10, 0x0008 },
+ { 0x0d, 0x006c },
+
+ { 0x1f, 0x0000 },
+ { 0x0d, 0xf880 },
+
+ { 0x1f, 0x0001 },
+ { 0x17, 0x0cc0 },
+
+ { 0x1f, 0x0001 },
+ { 0x0b, 0xa4d8 },
+ { 0x09, 0x281c },
+ { 0x07, 0x2883 },
+ { 0x0a, 0x6b35 },
+ { 0x1d, 0x3da4 },
+ { 0x1c, 0xeffd },
+ { 0x14, 0x7f52 },
+ { 0x18, 0x7fc6 },
+ { 0x08, 0x0601 },
+ { 0x06, 0x4063 },
+ { 0x10, 0xf074 },
+ { 0x1f, 0x0003 },
+ { 0x13, 0x0789 },
+ { 0x12, 0xf4bd },
+ { 0x1a, 0x04fd },
+ { 0x14, 0x84b0 },
+ { 0x1f, 0x0000 },
+ { 0x00, 0x9200 },
+
+ { 0x1f, 0x0005 },
+ { 0x01, 0x0340 },
+ { 0x1f, 0x0001 },
+ { 0x04, 0x4000 },
+ { 0x03, 0x1d21 },
+ { 0x02, 0x0c32 },
+ { 0x01, 0x0200 },
+ { 0x00, 0x5554 },
+ { 0x04, 0x4800 },
+ { 0x04, 0x4000 },
+ { 0x04, 0xf000 },
+ { 0x03, 0xdf01 },
+ { 0x02, 0xdf20 },
+ { 0x01, 0x101a },
+ { 0x00, 0xa0ff },
+ { 0x04, 0xf800 },
+ { 0x04, 0xf000 },
+ { 0x1f, 0x0000 },
+
+ { 0x1f, 0x0007 },
+ { 0x1e, 0x0023 },
+ { 0x16, 0x0000 },
+ { 0x1f, 0x0000 }
+ };
+
+ rtl_phy_write(ioaddr, phy_reg_init, ARRAY_SIZE(phy_reg_init));
}
static void rtl8102e_hw_phy_config(void __iomem *ioaddr)
@@ -1792,7 +2661,13 @@ static void rtl_hw_phy_config(struct net_device *dev)
rtl8168cp_2_hw_phy_config(ioaddr);
break;
case RTL_GIGA_MAC_VER_25:
- rtl8168d_hw_phy_config(ioaddr);
+ rtl8168d_1_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_26:
+ rtl8168d_2_hw_phy_config(ioaddr);
+ break;
+ case RTL_GIGA_MAC_VER_27:
+ rtl8168d_3_hw_phy_config(ioaddr);
break;
default:
@@ -2863,6 +3738,8 @@ static void rtl_hw_start_8168(struct net_device *dev)
break;
case RTL_GIGA_MAC_VER_25:
+ case RTL_GIGA_MAC_VER_26:
+ case RTL_GIGA_MAC_VER_27:
rtl_hw_start_8168d(ioaddr, pdev);
break;
@@ -3555,13 +4432,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/sb1000.c b/drivers/net/sb1000.c
index ee366c5a8fa3..c9c70ab0cce0 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -36,6 +36,7 @@ static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n";
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/interrupt.h>
#include <linux/errno.h>
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/sfe4001.c b/drivers/net/sfc/sfe4001.c
index cee00ad49b57..6dcdd448f33e 100644
--- a/drivers/net/sfc/sfe4001.c
+++ b/drivers/net/sfc/sfe4001.c
@@ -188,7 +188,7 @@ 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
@@ -204,7 +204,7 @@ static int sfn4111t_reset(struct efx_nic *efx)
falcon_write(efx, &reg, GPIO_CTL_REG_KER);
msleep(1);
- mutex_unlock(&efx->i2c_adap.bus_lock);
+ rt_mutex_unlock(&efx->i2c_adap.bus_lock);
ssleep(1);
return 0;
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
index f4d509015f75..1a3495c676c0 100644
--- a/drivers/net/sfc/tenxpress.c
+++ b/drivers/net/sfc/tenxpress.c
@@ -301,6 +301,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 +334,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);
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..161181a4b3d6 100644
--- a/drivers/net/sh_eth.c
+++ b/drivers/net/sh_eth.c
@@ -30,7 +30,7 @@
#include <linux/phy.h>
#include <linux/cache.h>
#include <linux/io.h>
-
+#include <linux/pm_runtime.h>
#include "sh_eth.h"
/* There is CPU dependent code */
@@ -298,16 +298,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 +1012,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 +1050,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 +1182,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 +1192,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 +1209,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 +1419,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 +1443,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 +1497,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/sis900.c b/drivers/net/sis900.c
index 97949d0a699b..c072f7f36acf 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -52,6 +52,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index 38a508b4aad9..b27156eaf267 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -73,6 +73,7 @@ static const char * const boot_msg =
/* Include files */
+#include <linux/capability.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 01f6811f1324..ba5eb14094ef 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -37,6 +37,7 @@
#include <linux/crc32.h>
#include <linux/dma-mapping.h>
#include <linux/debugfs.h>
+#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/mii.h>
#include <asm/irq.h>
@@ -3070,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);
@@ -3085,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/slip.c b/drivers/net/slip.c
index e17c535a577e..fe3cebb984de 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -67,6 +67,7 @@
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/bitops.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
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/stmmac/Kconfig b/drivers/net/stmmac/Kconfig
new file mode 100644
index 000000000000..35eaa5251d7f
--- /dev/null
+++ b/drivers/net/stmmac/Kconfig
@@ -0,0 +1,53 @@
+config STMMAC_ETH
+ tristate "STMicroelectronics 10/100/1000 Ethernet driver"
+ select MII
+ select PHYLIB
+ depends on NETDEVICES && CPU_SUBTYPE_ST40
+ help
+ This is the driver for the ST MAC 10/100/1000 on-chip Ethernet
+ controllers. ST Ethernet IPs are built around a Synopsys IP Core.
+
+if STMMAC_ETH
+
+config STMMAC_DA
+ bool "STMMAC DMA arbitration scheme"
+ default n
+ help
+ Selecting this option, rx has priority over Tx (only for Giga
+ Ethernet device).
+ By default, the DMA arbitration scheme is based on Round-robin
+ (rx:tx priority is 1:1).
+
+config STMMAC_DUAL_MAC
+ bool "STMMAC: dual mac support (EXPERIMENTAL)"
+ default n
+ depends on EXPERIMENTAL && STMMAC_ETH && !STMMAC_TIMER
+ help
+ Some ST SoCs (for example the stx7141 and stx7200c2) have two
+ Ethernet Controllers. This option turns on the second Ethernet
+ device on this kind of platforms.
+
+config STMMAC_TIMER
+ bool "STMMAC Timer optimisation"
+ default n
+ help
+ Use an external timer for mitigating the number of network
+ interrupts.
+
+choice
+ prompt "Select Timer device"
+ depends on STMMAC_TIMER
+
+config STMMAC_TMU_TIMER
+ bool "TMU channel 2"
+ depends on CPU_SH4
+ help
+
+config STMMAC_RTC_TIMER
+ bool "Real time clock"
+ depends on RTC_CLASS
+ help
+
+endchoice
+
+endif
diff --git a/drivers/net/stmmac/Makefile b/drivers/net/stmmac/Makefile
new file mode 100644
index 000000000000..b2d7a5564dfa
--- /dev/null
+++ b/drivers/net/stmmac/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_STMMAC_ETH) += stmmac.o
+stmmac-$(CONFIG_STMMAC_TIMER) += stmmac_timer.o
+stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o \
+ mac100.o gmac.o $(stmmac-y)
diff --git a/drivers/net/stmmac/common.h b/drivers/net/stmmac/common.h
new file mode 100644
index 000000000000..e49e5188e887
--- /dev/null
+++ b/drivers/net/stmmac/common.h
@@ -0,0 +1,330 @@
+/*******************************************************************************
+ STMMAC Common Header File
+
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include "descs.h"
+#include <linux/io.h>
+
+/* *********************************************
+ DMA CRS Control and Status Register Mapping
+ * *********************************************/
+#define DMA_BUS_MODE 0x00001000 /* Bus Mode */
+#define DMA_XMT_POLL_DEMAND 0x00001004 /* Transmit Poll Demand */
+#define DMA_RCV_POLL_DEMAND 0x00001008 /* Received Poll Demand */
+#define DMA_RCV_BASE_ADDR 0x0000100c /* Receive List Base */
+#define DMA_TX_BASE_ADDR 0x00001010 /* Transmit List Base */
+#define DMA_STATUS 0x00001014 /* Status Register */
+#define DMA_CONTROL 0x00001018 /* Ctrl (Operational Mode) */
+#define DMA_INTR_ENA 0x0000101c /* Interrupt Enable */
+#define DMA_MISSED_FRAME_CTR 0x00001020 /* Missed Frame Counter */
+#define DMA_CUR_TX_BUF_ADDR 0x00001050 /* Current Host Tx Buffer */
+#define DMA_CUR_RX_BUF_ADDR 0x00001054 /* Current Host Rx Buffer */
+
+/* ********************************
+ DMA Control register defines
+ * ********************************/
+#define DMA_CONTROL_ST 0x00002000 /* Start/Stop Transmission */
+#define DMA_CONTROL_SR 0x00000002 /* Start/Stop Receive */
+
+/* **************************************
+ DMA Interrupt Enable register defines
+ * **************************************/
+/**** NORMAL INTERRUPT ****/
+#define DMA_INTR_ENA_NIE 0x00010000 /* Normal Summary */
+#define DMA_INTR_ENA_TIE 0x00000001 /* Transmit Interrupt */
+#define DMA_INTR_ENA_TUE 0x00000004 /* Transmit Buffer Unavailable */
+#define DMA_INTR_ENA_RIE 0x00000040 /* Receive Interrupt */
+#define DMA_INTR_ENA_ERE 0x00004000 /* Early Receive */
+
+#define DMA_INTR_NORMAL (DMA_INTR_ENA_NIE | DMA_INTR_ENA_RIE | \
+ DMA_INTR_ENA_TIE)
+
+/**** ABNORMAL INTERRUPT ****/
+#define DMA_INTR_ENA_AIE 0x00008000 /* Abnormal Summary */
+#define DMA_INTR_ENA_FBE 0x00002000 /* Fatal Bus Error */
+#define DMA_INTR_ENA_ETE 0x00000400 /* Early Transmit */
+#define DMA_INTR_ENA_RWE 0x00000200 /* Receive Watchdog */
+#define DMA_INTR_ENA_RSE 0x00000100 /* Receive Stopped */
+#define DMA_INTR_ENA_RUE 0x00000080 /* Receive Buffer Unavailable */
+#define DMA_INTR_ENA_UNE 0x00000020 /* Tx Underflow */
+#define DMA_INTR_ENA_OVE 0x00000010 /* Receive Overflow */
+#define DMA_INTR_ENA_TJE 0x00000008 /* Transmit Jabber */
+#define DMA_INTR_ENA_TSE 0x00000002 /* Transmit Stopped */
+
+#define DMA_INTR_ABNORMAL (DMA_INTR_ENA_AIE | DMA_INTR_ENA_FBE | \
+ DMA_INTR_ENA_UNE)
+
+/* DMA default interrupt mask */
+#define DMA_INTR_DEFAULT_MASK (DMA_INTR_NORMAL | DMA_INTR_ABNORMAL)
+
+/* ****************************
+ * DMA Status register defines
+ * ****************************/
+#define DMA_STATUS_GPI 0x10000000 /* PMT interrupt */
+#define DMA_STATUS_GMI 0x08000000 /* MMC interrupt */
+#define DMA_STATUS_GLI 0x04000000 /* GMAC Line interface int. */
+#define DMA_STATUS_GMI 0x08000000
+#define DMA_STATUS_GLI 0x04000000
+#define DMA_STATUS_EB_MASK 0x00380000 /* Error Bits Mask */
+#define DMA_STATUS_EB_TX_ABORT 0x00080000 /* Error Bits - TX Abort */
+#define DMA_STATUS_EB_RX_ABORT 0x00100000 /* Error Bits - RX Abort */
+#define DMA_STATUS_TS_MASK 0x00700000 /* Transmit Process State */
+#define DMA_STATUS_TS_SHIFT 20
+#define DMA_STATUS_RS_MASK 0x000e0000 /* Receive Process State */
+#define DMA_STATUS_RS_SHIFT 17
+#define DMA_STATUS_NIS 0x00010000 /* Normal Interrupt Summary */
+#define DMA_STATUS_AIS 0x00008000 /* Abnormal Interrupt Summary */
+#define DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
+#define DMA_STATUS_FBI 0x00002000 /* Fatal Bus Error Interrupt */
+#define DMA_STATUS_ETI 0x00000400 /* Early Transmit Interrupt */
+#define DMA_STATUS_RWT 0x00000200 /* Receive Watchdog Timeout */
+#define DMA_STATUS_RPS 0x00000100 /* Receive Process Stopped */
+#define DMA_STATUS_RU 0x00000080 /* Receive Buffer Unavailable */
+#define DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
+#define DMA_STATUS_UNF 0x00000020 /* Transmit Underflow */
+#define DMA_STATUS_OVF 0x00000010 /* Receive Overflow */
+#define DMA_STATUS_TJT 0x00000008 /* Transmit Jabber Timeout */
+#define DMA_STATUS_TU 0x00000004 /* Transmit Buffer Unavailable */
+#define DMA_STATUS_TPS 0x00000002 /* Transmit Process Stopped */
+#define DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
+
+/* Other defines */
+#define HASH_TABLE_SIZE 64
+#define PAUSE_TIME 0x200
+
+/* Flow Control defines */
+#define FLOW_OFF 0
+#define FLOW_RX 1
+#define FLOW_TX 2
+#define FLOW_AUTO (FLOW_TX | FLOW_RX)
+
+/* DMA STORE-AND-FORWARD Operation Mode */
+#define SF_DMA_MODE 1
+
+#define HW_CSUM 1
+#define NO_HW_CSUM 0
+
+/* GMAC TX FIFO is 8K, Rx FIFO is 16K */
+#define BUF_SIZE_16KiB 16384
+#define BUF_SIZE_8KiB 8192
+#define BUF_SIZE_4KiB 4096
+#define BUF_SIZE_2KiB 2048
+
+/* Power Down and WOL */
+#define PMT_NOT_SUPPORTED 0
+#define PMT_SUPPORTED 1
+
+/* Common MAC defines */
+#define MAC_CTRL_REG 0x00000000 /* MAC Control */
+#define MAC_ENABLE_TX 0x00000008 /* Transmitter Enable */
+#define MAC_RNABLE_RX 0x00000004 /* Receiver Enable */
+
+/* MAC Management Counters register */
+#define MMC_CONTROL 0x00000100 /* MMC Control */
+#define MMC_HIGH_INTR 0x00000104 /* MMC High Interrupt */
+#define MMC_LOW_INTR 0x00000108 /* MMC Low Interrupt */
+#define MMC_HIGH_INTR_MASK 0x0000010c /* MMC High Interrupt Mask */
+#define MMC_LOW_INTR_MASK 0x00000110 /* MMC Low Interrupt Mask */
+
+#define MMC_CONTROL_MAX_FRM_MASK 0x0003ff8 /* Maximum Frame Size */
+#define MMC_CONTROL_MAX_FRM_SHIFT 3
+#define MMC_CONTROL_MAX_FRAME 0x7FF
+
+struct stmmac_extra_stats {
+ /* Transmit errors */
+ unsigned long tx_underflow ____cacheline_aligned;
+ unsigned long tx_carrier;
+ unsigned long tx_losscarrier;
+ unsigned long tx_heartbeat;
+ unsigned long tx_deferred;
+ unsigned long tx_vlan;
+ unsigned long tx_jabber;
+ unsigned long tx_frame_flushed;
+ unsigned long tx_payload_error;
+ unsigned long tx_ip_header_error;
+ /* Receive errors */
+ unsigned long rx_desc;
+ unsigned long rx_partial;
+ unsigned long rx_runt;
+ unsigned long rx_toolong;
+ unsigned long rx_collision;
+ unsigned long rx_crc;
+ unsigned long rx_lenght;
+ unsigned long rx_mii;
+ unsigned long rx_multicast;
+ unsigned long rx_gmac_overflow;
+ unsigned long rx_watchdog;
+ unsigned long da_rx_filter_fail;
+ unsigned long sa_rx_filter_fail;
+ unsigned long rx_missed_cntr;
+ unsigned long rx_overflow_cntr;
+ unsigned long rx_vlan;
+ /* Tx/Rx IRQ errors */
+ unsigned long tx_undeflow_irq;
+ unsigned long tx_process_stopped_irq;
+ unsigned long tx_jabber_irq;
+ unsigned long rx_overflow_irq;
+ unsigned long rx_buf_unav_irq;
+ unsigned long rx_process_stopped_irq;
+ unsigned long rx_watchdog_irq;
+ unsigned long tx_early_irq;
+ unsigned long fatal_bus_error_irq;
+ /* Extra info */
+ unsigned long threshold;
+ unsigned long tx_pkt_n;
+ unsigned long rx_pkt_n;
+ unsigned long poll_n;
+ unsigned long sched_timer_n;
+ unsigned long normal_irq_n;
+};
+
+/* GMAC core can compute the checksums in HW. */
+enum rx_frame_status {
+ good_frame = 0,
+ discard_frame = 1,
+ csum_none = 2,
+};
+
+static inline void stmmac_set_mac_addr(unsigned long ioaddr, u8 addr[6],
+ unsigned int high, unsigned int low)
+{
+ unsigned long data;
+
+ data = (addr[5] << 8) | addr[4];
+ writel(data, ioaddr + high);
+ data = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+ writel(data, ioaddr + low);
+
+ return;
+}
+
+static inline void stmmac_get_mac_addr(unsigned long ioaddr,
+ unsigned char *addr, unsigned int high,
+ unsigned int low)
+{
+ unsigned int hi_addr, lo_addr;
+
+ /* Read the MAC address from the hardware */
+ hi_addr = readl(ioaddr + high);
+ lo_addr = readl(ioaddr + low);
+
+ /* Extract the MAC address from the high and low words */
+ addr[0] = lo_addr & 0xff;
+ addr[1] = (lo_addr >> 8) & 0xff;
+ addr[2] = (lo_addr >> 16) & 0xff;
+ addr[3] = (lo_addr >> 24) & 0xff;
+ addr[4] = hi_addr & 0xff;
+ addr[5] = (hi_addr >> 8) & 0xff;
+
+ return;
+}
+
+struct stmmac_ops {
+ /* MAC core initialization */
+ void (*core_init) (unsigned long ioaddr) ____cacheline_aligned;
+ /* DMA core initialization */
+ int (*dma_init) (unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx);
+ /* Dump MAC registers */
+ void (*dump_mac_regs) (unsigned long ioaddr);
+ /* Dump DMA registers */
+ void (*dump_dma_regs) (unsigned long ioaddr);
+ /* Set tx/rx threshold in the csr6 register
+ * An invalid value enables the store-and-forward mode */
+ void (*dma_mode) (unsigned long ioaddr, int txmode, int rxmode);
+ /* To track extra statistic (if supported) */
+ void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
+ unsigned long ioaddr);
+ /* RX descriptor ring initialization */
+ void (*init_rx_desc) (struct dma_desc *p, unsigned int ring_size,
+ int disable_rx_ic);
+ /* TX descriptor ring initialization */
+ void (*init_tx_desc) (struct dma_desc *p, unsigned int ring_size);
+
+ /* Invoked by the xmit function to prepare the tx descriptor */
+ void (*prepare_tx_desc) (struct dma_desc *p, int is_fs, int len,
+ int csum_flag);
+ /* Set/get the owner of the descriptor */
+ void (*set_tx_owner) (struct dma_desc *p);
+ int (*get_tx_owner) (struct dma_desc *p);
+ /* Invoked by the xmit function to close the tx descriptor */
+ void (*close_tx_desc) (struct dma_desc *p);
+ /* Clean the tx descriptor as soon as the tx irq is received */
+ void (*release_tx_desc) (struct dma_desc *p);
+ /* Clear interrupt on tx frame completion. When this bit is
+ * set an interrupt happens as soon as the frame is transmitted */
+ void (*clear_tx_ic) (struct dma_desc *p);
+ /* Last tx segment reports the transmit status */
+ int (*get_tx_ls) (struct dma_desc *p);
+ /* Return the transmit status looking at the TDES1 */
+ int (*tx_status) (void *data, struct stmmac_extra_stats *x,
+ struct dma_desc *p, unsigned long ioaddr);
+ /* Get the buffer size from the descriptor */
+ int (*get_tx_len) (struct dma_desc *p);
+ /* Handle extra events on specific interrupts hw dependent */
+ void (*host_irq_status) (unsigned long ioaddr);
+ int (*get_rx_owner) (struct dma_desc *p);
+ void (*set_rx_owner) (struct dma_desc *p);
+ /* Get the receive frame size */
+ int (*get_rx_frame_len) (struct dma_desc *p);
+ /* Return the reception status looking at the RDES1 */
+ int (*rx_status) (void *data, struct stmmac_extra_stats *x,
+ struct dma_desc *p);
+ /* Multicast filter setting */
+ void (*set_filter) (struct net_device *dev);
+ /* Flow control setting */
+ void (*flow_ctrl) (unsigned long ioaddr, unsigned int duplex,
+ unsigned int fc, unsigned int pause_time);
+ /* Set power management mode (e.g. magic frame) */
+ void (*pmt) (unsigned long ioaddr, unsigned long mode);
+ /* Set/Get Unicast MAC addresses */
+ void (*set_umac_addr) (unsigned long ioaddr, unsigned char *addr,
+ unsigned int reg_n);
+ void (*get_umac_addr) (unsigned long ioaddr, unsigned char *addr,
+ unsigned int reg_n);
+};
+
+struct mac_link {
+ int port;
+ int duplex;
+ int speed;
+};
+
+struct mii_regs {
+ unsigned int addr; /* MII Address */
+ unsigned int data; /* MII Data */
+};
+
+struct hw_cap {
+ unsigned int version; /* Core Version register (GMAC) */
+ unsigned int pmt; /* Power-Down mode (GMAC) */
+ struct mac_link link;
+ struct mii_regs mii;
+};
+
+struct mac_device_info {
+ struct hw_cap hw;
+ struct stmmac_ops *ops;
+};
+
+struct mac_device_info *gmac_setup(unsigned long addr);
+struct mac_device_info *mac100_setup(unsigned long addr);
diff --git a/drivers/net/stmmac/descs.h b/drivers/net/stmmac/descs.h
new file mode 100644
index 000000000000..6d2a0b2f5e57
--- /dev/null
+++ b/drivers/net/stmmac/descs.h
@@ -0,0 +1,163 @@
+/*******************************************************************************
+ Header File to describe the DMA descriptors
+ Use enhanced descriptors in case of GMAC Cores.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+struct dma_desc {
+ /* Receive descriptor */
+ union {
+ struct {
+ /* RDES0 */
+ u32 reserved1:1;
+ u32 crc_error:1;
+ u32 dribbling:1;
+ u32 mii_error:1;
+ u32 receive_watchdog:1;
+ u32 frame_type:1;
+ u32 collision:1;
+ u32 frame_too_long:1;
+ u32 last_descriptor:1;
+ u32 first_descriptor:1;
+ u32 multicast_frame:1;
+ u32 run_frame:1;
+ u32 length_error:1;
+ u32 partial_frame_error:1;
+ u32 descriptor_error:1;
+ u32 error_summary:1;
+ u32 frame_length:14;
+ u32 filtering_fail:1;
+ u32 own:1;
+ /* RDES1 */
+ u32 buffer1_size:11;
+ u32 buffer2_size:11;
+ u32 reserved2:2;
+ u32 second_address_chained:1;
+ u32 end_ring:1;
+ u32 reserved3:5;
+ u32 disable_ic:1;
+ } rx;
+ struct {
+ /* RDES0 */
+ u32 payload_csum_error:1;
+ u32 crc_error:1;
+ u32 dribbling:1;
+ u32 error_gmii:1;
+ u32 receive_watchdog:1;
+ u32 frame_type:1;
+ u32 late_collision:1;
+ u32 ipc_csum_error:1;
+ u32 last_descriptor:1;
+ u32 first_descriptor:1;
+ u32 vlan_tag:1;
+ u32 overflow_error:1;
+ u32 length_error:1;
+ u32 sa_filter_fail:1;
+ u32 descriptor_error:1;
+ u32 error_summary:1;
+ u32 frame_length:14;
+ u32 da_filter_fail:1;
+ u32 own:1;
+ /* RDES1 */
+ u32 buffer1_size:13;
+ u32 reserved1:1;
+ u32 second_address_chained:1;
+ u32 end_ring:1;
+ u32 buffer2_size:13;
+ u32 reserved2:2;
+ u32 disable_ic:1;
+ } erx; /* -- enhanced -- */
+
+ /* Transmit descriptor */
+ struct {
+ /* TDES0 */
+ u32 deferred:1;
+ u32 underflow_error:1;
+ u32 excessive_deferral:1;
+ u32 collision_count:4;
+ u32 heartbeat_fail:1;
+ u32 excessive_collisions:1;
+ u32 late_collision:1;
+ u32 no_carrier:1;
+ u32 loss_carrier:1;
+ u32 reserved1:3;
+ u32 error_summary:1;
+ u32 reserved2:15;
+ u32 own:1;
+ /* TDES1 */
+ u32 buffer1_size:11;
+ u32 buffer2_size:11;
+ u32 reserved3:1;
+ u32 disable_padding:1;
+ u32 second_address_chained:1;
+ u32 end_ring:1;
+ u32 crc_disable:1;
+ u32 reserved4:2;
+ u32 first_segment:1;
+ u32 last_segment:1;
+ u32 interrupt:1;
+ } tx;
+ struct {
+ /* TDES0 */
+ u32 deferred:1;
+ u32 underflow_error:1;
+ u32 excessive_deferral:1;
+ u32 collision_count:4;
+ u32 vlan_frame:1;
+ u32 excessive_collisions:1;
+ u32 late_collision:1;
+ u32 no_carrier:1;
+ u32 loss_carrier:1;
+ u32 payload_error:1;
+ u32 frame_flushed:1;
+ u32 jabber_timeout:1;
+ u32 error_summary:1;
+ u32 ip_header_error:1;
+ u32 time_stamp_status:1;
+ u32 reserved1:2;
+ u32 second_address_chained:1;
+ u32 end_ring:1;
+ u32 checksum_insertion:2;
+ u32 reserved2:1;
+ u32 time_stamp_enable:1;
+ u32 disable_padding:1;
+ u32 crc_disable:1;
+ u32 first_segment:1;
+ u32 last_segment:1;
+ u32 interrupt:1;
+ u32 own:1;
+ /* TDES1 */
+ u32 buffer1_size:13;
+ u32 reserved3:3;
+ u32 buffer2_size:13;
+ u32 reserved4:3;
+ } etx; /* -- enhanced -- */
+ } des01;
+ unsigned int des2;
+ unsigned int des3;
+};
+
+/* Transmit checksum insertion control */
+enum tdes_csum_insertion {
+ cic_disabled = 0, /* Checksum Insertion Control */
+ cic_only_ip = 1, /* Only IP header */
+ cic_no_pseudoheader = 2, /* IP header but pseudoheader
+ * is not calculated */
+ cic_full = 3, /* IP header and pseudoheader */
+};
diff --git a/drivers/net/stmmac/gmac.c b/drivers/net/stmmac/gmac.c
new file mode 100644
index 000000000000..b624bb5bae0a
--- /dev/null
+++ b/drivers/net/stmmac/gmac.c
@@ -0,0 +1,693 @@
+/*******************************************************************************
+ This is the driver for the GMAC on-chip Ethernet controller for ST SoCs.
+ DWC Ether MAC 10/100/1000 Universal version 3.41a has been used for
+ developing this code.
+
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/netdevice.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#include "stmmac.h"
+#include "gmac.h"
+
+#undef GMAC_DEBUG
+/*#define GMAC_DEBUG*/
+#undef FRAME_FILTER_DEBUG
+/*#define FRAME_FILTER_DEBUG*/
+#ifdef GMAC_DEBUG
+#define DBG(fmt, args...) printk(fmt, ## args)
+#else
+#define DBG(fmt, args...) do { } while (0)
+#endif
+
+static void gmac_dump_regs(unsigned long ioaddr)
+{
+ int i;
+ pr_info("\t----------------------------------------------\n"
+ "\t GMAC registers (base addr = 0x%8x)\n"
+ "\t----------------------------------------------\n",
+ (unsigned int)ioaddr);
+
+ for (i = 0; i < 55; i++) {
+ int offset = i * 4;
+ pr_info("\tReg No. %d (offset 0x%x): 0x%08x\n", i,
+ offset, readl(ioaddr + offset));
+ }
+ return;
+}
+
+static int gmac_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx, u32 dma_rx)
+{
+ u32 value = readl(ioaddr + DMA_BUS_MODE);
+ /* DMA SW reset */
+ value |= DMA_BUS_MODE_SFT_RESET;
+ writel(value, ioaddr + DMA_BUS_MODE);
+ do {} while ((readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET));
+
+ value = /* DMA_BUS_MODE_FB | */ DMA_BUS_MODE_4PBL |
+ ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
+ (pbl << DMA_BUS_MODE_RPBL_SHIFT));
+
+#ifdef CONFIG_STMMAC_DA
+ value |= DMA_BUS_MODE_DA; /* Rx has priority over tx */
+#endif
+ writel(value, ioaddr + DMA_BUS_MODE);
+
+ /* Mask interrupts by writing to CSR7 */
+ writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+
+ /* The base address of the RX/TX descriptor lists must be written into
+ * DMA CSR3 and CSR4, respectively. */
+ writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
+ writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
+
+ return 0;
+}
+
+/* Transmit FIFO flush operation */
+static void gmac_flush_tx_fifo(unsigned long ioaddr)
+{
+ u32 csr6 = readl(ioaddr + DMA_CONTROL);
+ writel((csr6 | DMA_CONTROL_FTF), ioaddr + DMA_CONTROL);
+
+ do {} while ((readl(ioaddr + DMA_CONTROL) & DMA_CONTROL_FTF));
+}
+
+static void gmac_dma_operation_mode(unsigned long ioaddr, int txmode,
+ int rxmode)
+{
+ u32 csr6 = readl(ioaddr + DMA_CONTROL);
+
+ if (txmode == SF_DMA_MODE) {
+ DBG(KERN_DEBUG "GMAC: enabling TX store and forward mode\n");
+ /* Transmit COE type 2 cannot be done in cut-through mode. */
+ csr6 |= DMA_CONTROL_TSF;
+ /* Operating on second frame increase the performance
+ * especially when transmit store-and-forward is used.*/
+ csr6 |= DMA_CONTROL_OSF;
+ } else {
+ DBG(KERN_DEBUG "GMAC: disabling TX store and forward mode"
+ " (threshold = %d)\n", txmode);
+ csr6 &= ~DMA_CONTROL_TSF;
+ csr6 &= DMA_CONTROL_TC_TX_MASK;
+ /* Set the transmit threashold */
+ if (txmode <= 32)
+ csr6 |= DMA_CONTROL_TTC_32;
+ else if (txmode <= 64)
+ csr6 |= DMA_CONTROL_TTC_64;
+ else if (txmode <= 128)
+ csr6 |= DMA_CONTROL_TTC_128;
+ else if (txmode <= 192)
+ csr6 |= DMA_CONTROL_TTC_192;
+ else
+ csr6 |= DMA_CONTROL_TTC_256;
+ }
+
+ if (rxmode == SF_DMA_MODE) {
+ DBG(KERN_DEBUG "GMAC: enabling RX store and forward mode\n");
+ csr6 |= DMA_CONTROL_RSF;
+ } else {
+ DBG(KERN_DEBUG "GMAC: disabling RX store and forward mode"
+ " (threshold = %d)\n", rxmode);
+ csr6 &= ~DMA_CONTROL_RSF;
+ csr6 &= DMA_CONTROL_TC_RX_MASK;
+ if (rxmode <= 32)
+ csr6 |= DMA_CONTROL_RTC_32;
+ else if (rxmode <= 64)
+ csr6 |= DMA_CONTROL_RTC_64;
+ else if (rxmode <= 96)
+ csr6 |= DMA_CONTROL_RTC_96;
+ else
+ csr6 |= DMA_CONTROL_RTC_128;
+ }
+
+ writel(csr6, ioaddr + DMA_CONTROL);
+ return;
+}
+
+/* Not yet implemented --- no RMON module */
+static void gmac_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
+ unsigned long ioaddr)
+{
+ return;
+}
+
+static void gmac_dump_dma_regs(unsigned long ioaddr)
+{
+ int i;
+ pr_info(" DMA registers\n");
+ for (i = 0; i < 22; i++) {
+ if ((i < 9) || (i > 17)) {
+ int offset = i * 4;
+ pr_err("\t Reg No. %d (offset 0x%x): 0x%08x\n", i,
+ (DMA_BUS_MODE + offset),
+ readl(ioaddr + DMA_BUS_MODE + offset));
+ }
+ }
+ return;
+}
+
+static int gmac_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
+ struct dma_desc *p, unsigned long ioaddr)
+{
+ int ret = 0;
+ struct net_device_stats *stats = (struct net_device_stats *)data;
+
+ if (unlikely(p->des01.etx.error_summary)) {
+ DBG(KERN_ERR "GMAC TX error... 0x%08x\n", p->des01.etx);
+ if (unlikely(p->des01.etx.jabber_timeout)) {
+ DBG(KERN_ERR "\tjabber_timeout error\n");
+ x->tx_jabber++;
+ }
+
+ if (unlikely(p->des01.etx.frame_flushed)) {
+ DBG(KERN_ERR "\tframe_flushed error\n");
+ x->tx_frame_flushed++;
+ gmac_flush_tx_fifo(ioaddr);
+ }
+
+ if (unlikely(p->des01.etx.loss_carrier)) {
+ DBG(KERN_ERR "\tloss_carrier error\n");
+ x->tx_losscarrier++;
+ stats->tx_carrier_errors++;
+ }
+ if (unlikely(p->des01.etx.no_carrier)) {
+ DBG(KERN_ERR "\tno_carrier error\n");
+ x->tx_carrier++;
+ stats->tx_carrier_errors++;
+ }
+ if (unlikely(p->des01.etx.late_collision)) {
+ DBG(KERN_ERR "\tlate_collision error\n");
+ stats->collisions += p->des01.etx.collision_count;
+ }
+ if (unlikely(p->des01.etx.excessive_collisions)) {
+ DBG(KERN_ERR "\texcessive_collisions\n");
+ stats->collisions += p->des01.etx.collision_count;
+ }
+ if (unlikely(p->des01.etx.excessive_deferral)) {
+ DBG(KERN_INFO "\texcessive tx_deferral\n");
+ x->tx_deferred++;
+ }
+
+ if (unlikely(p->des01.etx.underflow_error)) {
+ DBG(KERN_ERR "\tunderflow error\n");
+ gmac_flush_tx_fifo(ioaddr);
+ x->tx_underflow++;
+ }
+
+ if (unlikely(p->des01.etx.ip_header_error)) {
+ DBG(KERN_ERR "\tTX IP header csum error\n");
+ x->tx_ip_header_error++;
+ }
+
+ if (unlikely(p->des01.etx.payload_error)) {
+ DBG(KERN_ERR "\tAddr/Payload csum error\n");
+ x->tx_payload_error++;
+ gmac_flush_tx_fifo(ioaddr);
+ }
+
+ ret = -1;
+ }
+
+ if (unlikely(p->des01.etx.deferred)) {
+ DBG(KERN_INFO "GMAC TX status: tx deferred\n");
+ x->tx_deferred++;
+ }
+#ifdef STMMAC_VLAN_TAG_USED
+ if (p->des01.etx.vlan_frame) {
+ DBG(KERN_INFO "GMAC TX status: VLAN frame\n");
+ x->tx_vlan++;
+ }
+#endif
+
+ return ret;
+}
+
+static int gmac_get_tx_len(struct dma_desc *p)
+{
+ return p->des01.etx.buffer1_size;
+}
+
+static int gmac_coe_rdes0(int ipc_err, int type, int payload_err)
+{
+ int ret = good_frame;
+ u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
+
+ /* bits 5 7 0 | Frame status
+ * ----------------------------------------------------------
+ * 0 0 0 | IEEE 802.3 Type frame (lenght < 1536 octects)
+ * 1 0 0 | IPv4/6 No CSUM errorS.
+ * 1 0 1 | IPv4/6 CSUM PAYLOAD error
+ * 1 1 0 | IPv4/6 CSUM IP HR error
+ * 1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
+ * 0 0 1 | IPv4/6 unsupported IP PAYLOAD
+ * 0 1 1 | COE bypassed.. no IPv4/6 frame
+ * 0 1 0 | Reserved.
+ */
+ if (status == 0x0) {
+ DBG(KERN_INFO "RX Des0 status: IEEE 802.3 Type frame.\n");
+ ret = good_frame;
+ } else if (status == 0x4) {
+ DBG(KERN_INFO "RX Des0 status: IPv4/6 No CSUM errorS.\n");
+ ret = good_frame;
+ } else if (status == 0x5) {
+ DBG(KERN_ERR "RX Des0 status: IPv4/6 Payload Error.\n");
+ ret = csum_none;
+ } else if (status == 0x6) {
+ DBG(KERN_ERR "RX Des0 status: IPv4/6 Header Error.\n");
+ ret = csum_none;
+ } else if (status == 0x7) {
+ DBG(KERN_ERR
+ "RX Des0 status: IPv4/6 Header and Payload Error.\n");
+ ret = csum_none;
+ } else if (status == 0x1) {
+ DBG(KERN_ERR
+ "RX Des0 status: IPv4/6 unsupported IP PAYLOAD.\n");
+ ret = discard_frame;
+ } else if (status == 0x3) {
+ DBG(KERN_ERR "RX Des0 status: No IPv4, IPv6 frame.\n");
+ ret = discard_frame;
+ }
+ return ret;
+}
+
+static int gmac_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
+ struct dma_desc *p)
+{
+ int ret = good_frame;
+ struct net_device_stats *stats = (struct net_device_stats *)data;
+
+ if (unlikely(p->des01.erx.error_summary)) {
+ DBG(KERN_ERR "GMAC RX Error Summary... 0x%08x\n", p->des01.erx);
+ if (unlikely(p->des01.erx.descriptor_error)) {
+ DBG(KERN_ERR "\tdescriptor error\n");
+ x->rx_desc++;
+ stats->rx_length_errors++;
+ }
+ if (unlikely(p->des01.erx.overflow_error)) {
+ DBG(KERN_ERR "\toverflow error\n");
+ x->rx_gmac_overflow++;
+ }
+
+ if (unlikely(p->des01.erx.ipc_csum_error))
+ DBG(KERN_ERR "\tIPC Csum Error/Giant frame\n");
+
+ if (unlikely(p->des01.erx.late_collision)) {
+ DBG(KERN_ERR "\tlate_collision error\n");
+ stats->collisions++;
+ stats->collisions++;
+ }
+ if (unlikely(p->des01.erx.receive_watchdog)) {
+ DBG(KERN_ERR "\treceive_watchdog error\n");
+ x->rx_watchdog++;
+ }
+ if (unlikely(p->des01.erx.error_gmii)) {
+ DBG(KERN_ERR "\tReceive Error\n");
+ x->rx_mii++;
+ }
+ if (unlikely(p->des01.erx.crc_error)) {
+ DBG(KERN_ERR "\tCRC error\n");
+ x->rx_crc++;
+ stats->rx_crc_errors++;
+ }
+ ret = discard_frame;
+ }
+
+ /* After a payload csum error, the ES bit is set.
+ * It doesn't match with the information reported into the databook.
+ * At any rate, we need to understand if the CSUM hw computation is ok
+ * and report this info to the upper layers. */
+ ret = gmac_coe_rdes0(p->des01.erx.ipc_csum_error,
+ p->des01.erx.frame_type, p->des01.erx.payload_csum_error);
+
+ if (unlikely(p->des01.erx.dribbling)) {
+ DBG(KERN_ERR "GMAC RX: dribbling error\n");
+ ret = discard_frame;
+ }
+ if (unlikely(p->des01.erx.sa_filter_fail)) {
+ DBG(KERN_ERR "GMAC RX : Source Address filter fail\n");
+ x->sa_rx_filter_fail++;
+ ret = discard_frame;
+ }
+ if (unlikely(p->des01.erx.da_filter_fail)) {
+ DBG(KERN_ERR "GMAC RX : Destination Address filter fail\n");
+ x->da_rx_filter_fail++;
+ ret = discard_frame;
+ }
+ if (unlikely(p->des01.erx.length_error)) {
+ DBG(KERN_ERR "GMAC RX: length_error error\n");
+ x->rx_lenght++;
+ ret = discard_frame;
+ }
+#ifdef STMMAC_VLAN_TAG_USED
+ if (p->des01.erx.vlan_tag) {
+ DBG(KERN_INFO "GMAC RX: VLAN frame tagged\n");
+ x->rx_vlan++;
+ }
+#endif
+ return ret;
+}
+
+static void gmac_irq_status(unsigned long ioaddr)
+{
+ u32 intr_status = readl(ioaddr + GMAC_INT_STATUS);
+
+ /* Not used events (e.g. MMC interrupts) are not handled. */
+ if ((intr_status & mmc_tx_irq))
+ DBG(KERN_DEBUG "GMAC: MMC tx interrupt: 0x%08x\n",
+ readl(ioaddr + GMAC_MMC_TX_INTR));
+ if (unlikely(intr_status & mmc_rx_irq))
+ DBG(KERN_DEBUG "GMAC: MMC rx interrupt: 0x%08x\n",
+ readl(ioaddr + GMAC_MMC_RX_INTR));
+ if (unlikely(intr_status & mmc_rx_csum_offload_irq))
+ DBG(KERN_DEBUG "GMAC: MMC rx csum offload: 0x%08x\n",
+ readl(ioaddr + GMAC_MMC_RX_CSUM_OFFLOAD));
+ if (unlikely(intr_status & pmt_irq)) {
+ DBG(KERN_DEBUG "GMAC: received Magic frame\n");
+ /* clear the PMT bits 5 and 6 by reading the PMT
+ * status register. */
+ readl(ioaddr + GMAC_PMT);
+ }
+
+ return;
+}
+
+static void gmac_core_init(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + GMAC_CONTROL);
+ value |= GMAC_CORE_INIT;
+ writel(value, ioaddr + GMAC_CONTROL);
+
+ /* STBus Bridge Configuration */
+ /*writel(0xc5608, ioaddr + 0x00007000);*/
+
+ /* Freeze MMC counters */
+ writel(0x8, ioaddr + GMAC_MMC_CTRL);
+ /* Mask GMAC interrupts */
+ writel(0x207, ioaddr + GMAC_INT_MASK);
+
+#ifdef STMMAC_VLAN_TAG_USED
+ /* Tag detection without filtering */
+ writel(0x0, ioaddr + GMAC_VLAN_TAG);
+#endif
+ return;
+}
+
+static void gmac_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
+ unsigned int reg_n)
+{
+ stmmac_set_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
+ GMAC_ADDR_LOW(reg_n));
+}
+
+static void gmac_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
+ unsigned int reg_n)
+{
+ stmmac_get_mac_addr(ioaddr, addr, GMAC_ADDR_HIGH(reg_n),
+ GMAC_ADDR_LOW(reg_n));
+}
+
+static void gmac_set_filter(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ unsigned int value = 0;
+
+ DBG(KERN_INFO "%s: # mcasts %d, # unicast %d\n",
+ __func__, dev->mc_count, dev->uc_count);
+
+ if (dev->flags & IFF_PROMISC)
+ value = GMAC_FRAME_FILTER_PR;
+ else if ((dev->mc_count > HASH_TABLE_SIZE)
+ || (dev->flags & IFF_ALLMULTI)) {
+ value = GMAC_FRAME_FILTER_PM; /* pass all multi */
+ writel(0xffffffff, ioaddr + GMAC_HASH_HIGH);
+ writel(0xffffffff, ioaddr + GMAC_HASH_LOW);
+ } else if (dev->mc_count > 0) {
+ int i;
+ u32 mc_filter[2];
+ struct dev_mc_list *mclist;
+
+ /* Hash filter for multicast */
+ value = GMAC_FRAME_FILTER_HMC;
+
+ memset(mc_filter, 0, sizeof(mc_filter));
+ for (i = 0, mclist = dev->mc_list;
+ mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+ /* The upper 6 bits of the calculated CRC are used to
+ index the contens of the hash table */
+ int bit_nr =
+ bitrev32(~crc32_le(~0, mclist->dmi_addr, 6)) >> 26;
+ /* The most significant bit determines the register to
+ * use (H/L) while the other 5 bits determine the bit
+ * within the register. */
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ }
+ writel(mc_filter[0], ioaddr + GMAC_HASH_LOW);
+ writel(mc_filter[1], ioaddr + GMAC_HASH_HIGH);
+ }
+
+ /* Handle multiple unicast addresses (perfect filtering)*/
+ if (dev->uc_count > GMAC_MAX_UNICAST_ADDRESSES)
+ /* Switch to promiscuous mode is more than 16 addrs
+ are required */
+ value |= GMAC_FRAME_FILTER_PR;
+ else {
+ int i;
+ struct dev_addr_list *uc_ptr = dev->uc_list;
+
+ for (i = 0; i < dev->uc_count; i++) {
+ gmac_set_umac_addr(ioaddr, uc_ptr->da_addr,
+ i + 1);
+
+ DBG(KERN_INFO "\t%d "
+ "- Unicast addr %02x:%02x:%02x:%02x:%02x:"
+ "%02x\n", i + 1,
+ uc_ptr->da_addr[0], uc_ptr->da_addr[1],
+ uc_ptr->da_addr[2], uc_ptr->da_addr[3],
+ uc_ptr->da_addr[4], uc_ptr->da_addr[5]);
+ uc_ptr = uc_ptr->next;
+ }
+ }
+
+#ifdef FRAME_FILTER_DEBUG
+ /* Enable Receive all mode (to debug filtering_fail errors) */
+ value |= GMAC_FRAME_FILTER_RA;
+#endif
+ writel(value, ioaddr + GMAC_FRAME_FILTER);
+
+ DBG(KERN_INFO "\tFrame Filter reg: 0x%08x\n\tHash regs: "
+ "HI 0x%08x, LO 0x%08x\n", readl(ioaddr + GMAC_FRAME_FILTER),
+ readl(ioaddr + GMAC_HASH_HIGH), readl(ioaddr + GMAC_HASH_LOW));
+
+ return;
+}
+
+static void gmac_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
+ unsigned int fc, unsigned int pause_time)
+{
+ unsigned int flow = 0;
+
+ DBG(KERN_DEBUG "GMAC Flow-Control:\n");
+ if (fc & FLOW_RX) {
+ DBG(KERN_DEBUG "\tReceive Flow-Control ON\n");
+ flow |= GMAC_FLOW_CTRL_RFE;
+ }
+ if (fc & FLOW_TX) {
+ DBG(KERN_DEBUG "\tTransmit Flow-Control ON\n");
+ flow |= GMAC_FLOW_CTRL_TFE;
+ }
+
+ if (duplex) {
+ DBG(KERN_DEBUG "\tduplex mode: pause time: %d\n", pause_time);
+ flow |= (pause_time << GMAC_FLOW_CTRL_PT_SHIFT);
+ }
+
+ writel(flow, ioaddr + GMAC_FLOW_CTRL);
+ return;
+}
+
+static void gmac_pmt(unsigned long ioaddr, unsigned long mode)
+{
+ unsigned int pmt = 0;
+
+ if (mode == WAKE_MAGIC) {
+ DBG(KERN_DEBUG "GMAC: WOL Magic frame\n");
+ pmt |= power_down | magic_pkt_en;
+ } else if (mode == WAKE_UCAST) {
+ DBG(KERN_DEBUG "GMAC: WOL on global unicast\n");
+ pmt |= global_unicast;
+ }
+
+ writel(pmt, ioaddr + GMAC_PMT);
+ return;
+}
+
+static void gmac_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
+ int disable_rx_ic)
+{
+ int i;
+ for (i = 0; i < ring_size; i++) {
+ p->des01.erx.own = 1;
+ p->des01.erx.buffer1_size = BUF_SIZE_8KiB - 1;
+ /* To support jumbo frames */
+ p->des01.erx.buffer2_size = BUF_SIZE_8KiB - 1;
+ if (i == ring_size - 1)
+ p->des01.erx.end_ring = 1;
+ if (disable_rx_ic)
+ p->des01.erx.disable_ic = 1;
+ p++;
+ }
+ return;
+}
+
+static void gmac_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
+{
+ int i;
+
+ for (i = 0; i < ring_size; i++) {
+ p->des01.etx.own = 0;
+ if (i == ring_size - 1)
+ p->des01.etx.end_ring = 1;
+ p++;
+ }
+
+ return;
+}
+
+static int gmac_get_tx_owner(struct dma_desc *p)
+{
+ return p->des01.etx.own;
+}
+
+static int gmac_get_rx_owner(struct dma_desc *p)
+{
+ return p->des01.erx.own;
+}
+
+static void gmac_set_tx_owner(struct dma_desc *p)
+{
+ p->des01.etx.own = 1;
+}
+
+static void gmac_set_rx_owner(struct dma_desc *p)
+{
+ p->des01.erx.own = 1;
+}
+
+static int gmac_get_tx_ls(struct dma_desc *p)
+{
+ return p->des01.etx.last_segment;
+}
+
+static void gmac_release_tx_desc(struct dma_desc *p)
+{
+ int ter = p->des01.etx.end_ring;
+
+ memset(p, 0, sizeof(struct dma_desc));
+ p->des01.etx.end_ring = ter;
+
+ return;
+}
+
+static void gmac_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
+ int csum_flag)
+{
+ p->des01.etx.first_segment = is_fs;
+ if (unlikely(len > BUF_SIZE_4KiB)) {
+ p->des01.etx.buffer1_size = BUF_SIZE_4KiB;
+ p->des01.etx.buffer2_size = len - BUF_SIZE_4KiB;
+ } else {
+ p->des01.etx.buffer1_size = len;
+ }
+ if (likely(csum_flag))
+ p->des01.etx.checksum_insertion = cic_full;
+}
+
+static void gmac_clear_tx_ic(struct dma_desc *p)
+{
+ p->des01.etx.interrupt = 0;
+}
+
+static void gmac_close_tx_desc(struct dma_desc *p)
+{
+ p->des01.etx.last_segment = 1;
+ p->des01.etx.interrupt = 1;
+}
+
+static int gmac_get_rx_frame_len(struct dma_desc *p)
+{
+ return p->des01.erx.frame_length;
+}
+
+struct stmmac_ops gmac_driver = {
+ .core_init = gmac_core_init,
+ .dump_mac_regs = gmac_dump_regs,
+ .dma_init = gmac_dma_init,
+ .dump_dma_regs = gmac_dump_dma_regs,
+ .dma_mode = gmac_dma_operation_mode,
+ .dma_diagnostic_fr = gmac_dma_diagnostic_fr,
+ .tx_status = gmac_get_tx_frame_status,
+ .rx_status = gmac_get_rx_frame_status,
+ .get_tx_len = gmac_get_tx_len,
+ .set_filter = gmac_set_filter,
+ .flow_ctrl = gmac_flow_ctrl,
+ .pmt = gmac_pmt,
+ .init_rx_desc = gmac_init_rx_desc,
+ .init_tx_desc = gmac_init_tx_desc,
+ .get_tx_owner = gmac_get_tx_owner,
+ .get_rx_owner = gmac_get_rx_owner,
+ .release_tx_desc = gmac_release_tx_desc,
+ .prepare_tx_desc = gmac_prepare_tx_desc,
+ .clear_tx_ic = gmac_clear_tx_ic,
+ .close_tx_desc = gmac_close_tx_desc,
+ .get_tx_ls = gmac_get_tx_ls,
+ .set_tx_owner = gmac_set_tx_owner,
+ .set_rx_owner = gmac_set_rx_owner,
+ .get_rx_frame_len = gmac_get_rx_frame_len,
+ .host_irq_status = gmac_irq_status,
+ .set_umac_addr = gmac_set_umac_addr,
+ .get_umac_addr = gmac_get_umac_addr,
+};
+
+struct mac_device_info *gmac_setup(unsigned long ioaddr)
+{
+ struct mac_device_info *mac;
+ u32 uid = readl(ioaddr + GMAC_VERSION);
+
+ pr_info("\tGMAC - user ID: 0x%x, Synopsys ID: 0x%x\n",
+ ((uid & 0x0000ff00) >> 8), (uid & 0x000000ff));
+
+ mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
+
+ mac->ops = &gmac_driver;
+ mac->hw.pmt = PMT_SUPPORTED;
+ mac->hw.link.port = GMAC_CONTROL_PS;
+ mac->hw.link.duplex = GMAC_CONTROL_DM;
+ mac->hw.link.speed = GMAC_CONTROL_FES;
+ mac->hw.mii.addr = GMAC_MII_ADDR;
+ mac->hw.mii.data = GMAC_MII_DATA;
+
+ return mac;
+}
diff --git a/drivers/net/stmmac/gmac.h b/drivers/net/stmmac/gmac.h
new file mode 100644
index 000000000000..684a363120a9
--- /dev/null
+++ b/drivers/net/stmmac/gmac.h
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#define GMAC_CONTROL 0x00000000 /* Configuration */
+#define GMAC_FRAME_FILTER 0x00000004 /* Frame Filter */
+#define GMAC_HASH_HIGH 0x00000008 /* Multicast Hash Table High */
+#define GMAC_HASH_LOW 0x0000000c /* Multicast Hash Table Low */
+#define GMAC_MII_ADDR 0x00000010 /* MII Address */
+#define GMAC_MII_DATA 0x00000014 /* MII Data */
+#define GMAC_FLOW_CTRL 0x00000018 /* Flow Control */
+#define GMAC_VLAN_TAG 0x0000001c /* VLAN Tag */
+#define GMAC_VERSION 0x00000020 /* GMAC CORE Version */
+#define GMAC_WAKEUP_FILTER 0x00000028 /* Wake-up Frame Filter */
+
+#define GMAC_INT_STATUS 0x00000038 /* interrupt status register */
+enum gmac_irq_status {
+ time_stamp_irq = 0x0200,
+ mmc_rx_csum_offload_irq = 0x0080,
+ mmc_tx_irq = 0x0040,
+ mmc_rx_irq = 0x0020,
+ mmc_irq = 0x0010,
+ pmt_irq = 0x0008,
+ pcs_ane_irq = 0x0004,
+ pcs_link_irq = 0x0002,
+ rgmii_irq = 0x0001,
+};
+#define GMAC_INT_MASK 0x0000003c /* interrupt mask register */
+
+/* PMT Control and Status */
+#define GMAC_PMT 0x0000002c
+enum power_event {
+ pointer_reset = 0x80000000,
+ global_unicast = 0x00000200,
+ wake_up_rx_frame = 0x00000040,
+ magic_frame = 0x00000020,
+ wake_up_frame_en = 0x00000004,
+ magic_pkt_en = 0x00000002,
+ power_down = 0x00000001,
+};
+
+/* GMAC HW ADDR regs */
+#define GMAC_ADDR_HIGH(reg) (0x00000040+(reg * 8))
+#define GMAC_ADDR_LOW(reg) (0x00000044+(reg * 8))
+#define GMAC_MAX_UNICAST_ADDRESSES 16
+
+#define GMAC_AN_CTRL 0x000000c0 /* AN control */
+#define GMAC_AN_STATUS 0x000000c4 /* AN status */
+#define GMAC_ANE_ADV 0x000000c8 /* Auto-Neg. Advertisement */
+#define GMAC_ANE_LINK 0x000000cc /* Auto-Neg. link partener ability */
+#define GMAC_ANE_EXP 0x000000d0 /* ANE expansion */
+#define GMAC_TBI 0x000000d4 /* TBI extend status */
+#define GMAC_GMII_STATUS 0x000000d8 /* S/R-GMII status */
+
+/* GMAC Configuration defines */
+#define GMAC_CONTROL_TC 0x01000000 /* Transmit Conf. in RGMII/SGMII */
+#define GMAC_CONTROL_WD 0x00800000 /* Disable Watchdog on receive */
+#define GMAC_CONTROL_JD 0x00400000 /* Jabber disable */
+#define GMAC_CONTROL_BE 0x00200000 /* Frame Burst Enable */
+#define GMAC_CONTROL_JE 0x00100000 /* Jumbo frame */
+enum inter_frame_gap {
+ GMAC_CONTROL_IFG_88 = 0x00040000,
+ GMAC_CONTROL_IFG_80 = 0x00020000,
+ GMAC_CONTROL_IFG_40 = 0x000e0000,
+};
+#define GMAC_CONTROL_DCRS 0x00010000 /* Disable carrier sense during tx */
+#define GMAC_CONTROL_PS 0x00008000 /* Port Select 0:GMI 1:MII */
+#define GMAC_CONTROL_FES 0x00004000 /* Speed 0:10 1:100 */
+#define GMAC_CONTROL_DO 0x00002000 /* Disable Rx Own */
+#define GMAC_CONTROL_LM 0x00001000 /* Loop-back mode */
+#define GMAC_CONTROL_DM 0x00000800 /* Duplex Mode */
+#define GMAC_CONTROL_IPC 0x00000400 /* Checksum Offload */
+#define GMAC_CONTROL_DR 0x00000200 /* Disable Retry */
+#define GMAC_CONTROL_LUD 0x00000100 /* Link up/down */
+#define GMAC_CONTROL_ACS 0x00000080 /* Automatic Pad Stripping */
+#define GMAC_CONTROL_DC 0x00000010 /* Deferral Check */
+#define GMAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
+#define GMAC_CONTROL_RE 0x00000004 /* Receiver Enable */
+
+#define GMAC_CORE_INIT (GMAC_CONTROL_JD | GMAC_CONTROL_PS | GMAC_CONTROL_ACS | \
+ GMAC_CONTROL_IPC | GMAC_CONTROL_JE | GMAC_CONTROL_BE)
+
+/* GMAC Frame Filter defines */
+#define GMAC_FRAME_FILTER_PR 0x00000001 /* Promiscuous Mode */
+#define GMAC_FRAME_FILTER_HUC 0x00000002 /* Hash Unicast */
+#define GMAC_FRAME_FILTER_HMC 0x00000004 /* Hash Multicast */
+#define GMAC_FRAME_FILTER_DAIF 0x00000008 /* DA Inverse Filtering */
+#define GMAC_FRAME_FILTER_PM 0x00000010 /* Pass all multicast */
+#define GMAC_FRAME_FILTER_DBF 0x00000020 /* Disable Broadcast frames */
+#define GMAC_FRAME_FILTER_SAIF 0x00000100 /* Inverse Filtering */
+#define GMAC_FRAME_FILTER_SAF 0x00000200 /* Source Address Filter */
+#define GMAC_FRAME_FILTER_HPF 0x00000400 /* Hash or perfect Filter */
+#define GMAC_FRAME_FILTER_RA 0x80000000 /* Receive all mode */
+/* GMII ADDR defines */
+#define GMAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
+#define GMAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */
+/* GMAC FLOW CTRL defines */
+#define GMAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
+#define GMAC_FLOW_CTRL_PT_SHIFT 16
+#define GMAC_FLOW_CTRL_RFE 0x00000004 /* Rx Flow Control Enable */
+#define GMAC_FLOW_CTRL_TFE 0x00000002 /* Tx Flow Control Enable */
+#define GMAC_FLOW_CTRL_FCB_BPA 0x00000001 /* Flow Control Busy ... */
+
+/*--- DMA BLOCK defines ---*/
+/* DMA Bus Mode register defines */
+#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
+#define DMA_BUS_MODE_DA 0x00000002 /* Arbitration scheme */
+#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
+#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
+/* Programmable burst length (passed thorugh platform)*/
+#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
+#define DMA_BUS_MODE_PBL_SHIFT 8
+
+enum rx_tx_priority_ratio {
+ double_ratio = 0x00004000, /*2:1 */
+ triple_ratio = 0x00008000, /*3:1 */
+ quadruple_ratio = 0x0000c000, /*4:1 */
+};
+
+#define DMA_BUS_MODE_FB 0x00010000 /* Fixed burst */
+#define DMA_BUS_MODE_RPBL_MASK 0x003e0000 /* Rx-Programmable Burst Len */
+#define DMA_BUS_MODE_RPBL_SHIFT 17
+#define DMA_BUS_MODE_USP 0x00800000
+#define DMA_BUS_MODE_4PBL 0x01000000
+#define DMA_BUS_MODE_AAL 0x02000000
+
+/* DMA CRS Control and Status Register Mapping */
+#define DMA_HOST_TX_DESC 0x00001048 /* Current Host Tx descriptor */
+#define DMA_HOST_RX_DESC 0x0000104c /* Current Host Rx descriptor */
+/* DMA Bus Mode register defines */
+#define DMA_BUS_PR_RATIO_MASK 0x0000c000 /* Rx/Tx priority ratio */
+#define DMA_BUS_PR_RATIO_SHIFT 14
+#define DMA_BUS_FB 0x00010000 /* Fixed Burst */
+
+/* DMA operation mode defines (start/stop tx/rx are placed in common header)*/
+#define DMA_CONTROL_DT 0x04000000 /* Disable Drop TCP/IP csum error */
+#define DMA_CONTROL_RSF 0x02000000 /* Receive Store and Forward */
+#define DMA_CONTROL_DFF 0x01000000 /* Disaable flushing */
+/* Theshold for Activating the FC */
+enum rfa {
+ act_full_minus_1 = 0x00800000,
+ act_full_minus_2 = 0x00800200,
+ act_full_minus_3 = 0x00800400,
+ act_full_minus_4 = 0x00800600,
+};
+/* Theshold for Deactivating the FC */
+enum rfd {
+ deac_full_minus_1 = 0x00400000,
+ deac_full_minus_2 = 0x00400800,
+ deac_full_minus_3 = 0x00401000,
+ deac_full_minus_4 = 0x00401800,
+};
+#define DMA_CONTROL_TSF 0x00200000 /* Transmit Store and Forward */
+#define DMA_CONTROL_FTF 0x00100000 /* Flush transmit FIFO */
+
+enum ttc_control {
+ DMA_CONTROL_TTC_64 = 0x00000000,
+ DMA_CONTROL_TTC_128 = 0x00004000,
+ DMA_CONTROL_TTC_192 = 0x00008000,
+ DMA_CONTROL_TTC_256 = 0x0000c000,
+ DMA_CONTROL_TTC_40 = 0x00010000,
+ DMA_CONTROL_TTC_32 = 0x00014000,
+ DMA_CONTROL_TTC_24 = 0x00018000,
+ DMA_CONTROL_TTC_16 = 0x0001c000,
+};
+#define DMA_CONTROL_TC_TX_MASK 0xfffe3fff
+
+#define DMA_CONTROL_EFC 0x00000100
+#define DMA_CONTROL_FEF 0x00000080
+#define DMA_CONTROL_FUF 0x00000040
+
+enum rtc_control {
+ DMA_CONTROL_RTC_64 = 0x00000000,
+ DMA_CONTROL_RTC_32 = 0x00000008,
+ DMA_CONTROL_RTC_96 = 0x00000010,
+ DMA_CONTROL_RTC_128 = 0x00000018,
+};
+#define DMA_CONTROL_TC_RX_MASK 0xffffffe7
+
+#define DMA_CONTROL_OSF 0x00000004 /* Operate on second frame */
+
+/* MMC registers offset */
+#define GMAC_MMC_CTRL 0x100
+#define GMAC_MMC_RX_INTR 0x104
+#define GMAC_MMC_TX_INTR 0x108
+#define GMAC_MMC_RX_CSUM_OFFLOAD 0x208
diff --git a/drivers/net/stmmac/mac100.c b/drivers/net/stmmac/mac100.c
new file mode 100644
index 000000000000..625171b6062b
--- /dev/null
+++ b/drivers/net/stmmac/mac100.c
@@ -0,0 +1,517 @@
+/*******************************************************************************
+ This is the driver for the MAC 10/100 on-chip Ethernet controller
+ currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
+
+ DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
+ this code.
+
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/netdevice.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#include "common.h"
+#include "mac100.h"
+
+#undef MAC100_DEBUG
+/*#define MAC100_DEBUG*/
+#ifdef MAC100_DEBUG
+#define DBG(fmt, args...) printk(fmt, ## args)
+#else
+#define DBG(fmt, args...) do { } while (0)
+#endif
+
+static void mac100_core_init(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + MAC_CONTROL);
+
+ writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL);
+
+#ifdef STMMAC_VLAN_TAG_USED
+ writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);
+#endif
+ return;
+}
+
+static void mac100_dump_mac_regs(unsigned long ioaddr)
+{
+ pr_info("\t----------------------------------------------\n"
+ "\t MAC100 CSR (base addr = 0x%8x)\n"
+ "\t----------------------------------------------\n",
+ (unsigned int)ioaddr);
+ pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
+ readl(ioaddr + MAC_CONTROL));
+ pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
+ readl(ioaddr + MAC_ADDR_HIGH));
+ pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW,
+ readl(ioaddr + MAC_ADDR_LOW));
+ pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
+ MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
+ pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n",
+ MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
+ pr_info("\tflow control (offset 0x%x): 0x%08x\n",
+ MAC_FLOW_CTRL, readl(ioaddr + MAC_FLOW_CTRL));
+ pr_info("\tVLAN1 tag (offset 0x%x): 0x%08x\n", MAC_VLAN1,
+ readl(ioaddr + MAC_VLAN1));
+ pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
+ readl(ioaddr + MAC_VLAN2));
+ pr_info("\n\tMAC management counter registers\n");
+ pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n",
+ MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
+ pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
+ MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
+ pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n",
+ MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
+ pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
+ MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
+ pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n",
+ MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
+ return;
+}
+
+static int mac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
+ u32 dma_rx)
+{
+ u32 value = readl(ioaddr + DMA_BUS_MODE);
+ /* DMA SW reset */
+ value |= DMA_BUS_MODE_SFT_RESET;
+ writel(value, ioaddr + DMA_BUS_MODE);
+ do {} while ((readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET));
+
+ /* Enable Application Access by writing to DMA CSR0 */
+ writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
+ ioaddr + DMA_BUS_MODE);
+
+ /* Mask interrupts by writing to CSR7 */
+ writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
+
+ /* The base address of the RX/TX descriptor lists must be written into
+ * DMA CSR3 and CSR4, respectively. */
+ writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
+ writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
+
+ return 0;
+}
+
+/* Store and Forward capability is not used at all..
+ * The transmit threshold can be programmed by
+ * setting the TTC bits in the DMA control register.*/
+static void mac100_dma_operation_mode(unsigned long ioaddr, int txmode,
+ int rxmode)
+{
+ u32 csr6 = readl(ioaddr + DMA_CONTROL);
+
+ if (txmode <= 32)
+ csr6 |= DMA_CONTROL_TTC_32;
+ else if (txmode <= 64)
+ csr6 |= DMA_CONTROL_TTC_64;
+ else
+ csr6 |= DMA_CONTROL_TTC_128;
+
+ writel(csr6, ioaddr + DMA_CONTROL);
+
+ return;
+}
+
+static void mac100_dump_dma_regs(unsigned long ioaddr)
+{
+ int i;
+
+ DBG(KERN_DEBUG "MAC100 DMA CSR \n");
+ for (i = 0; i < 9; i++)
+ pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i,
+ (DMA_BUS_MODE + i * 4),
+ readl(ioaddr + DMA_BUS_MODE + i * 4));
+ DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n",
+ DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR));
+ DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n",
+ DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
+ return;
+}
+
+/* DMA controller has two counters to track the number of
+ the receive missed frames. */
+static void mac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
+ unsigned long ioaddr)
+{
+ struct net_device_stats *stats = (struct net_device_stats *)data;
+ u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
+
+ if (unlikely(csr8)) {
+ if (csr8 & DMA_MISSED_FRAME_OVE) {
+ stats->rx_over_errors += 0x800;
+ x->rx_overflow_cntr += 0x800;
+ } else {
+ unsigned int ove_cntr;
+ ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
+ stats->rx_over_errors += ove_cntr;
+ x->rx_overflow_cntr += ove_cntr;
+ }
+
+ if (csr8 & DMA_MISSED_FRAME_OVE_M) {
+ stats->rx_missed_errors += 0xffff;
+ x->rx_missed_cntr += 0xffff;
+ } else {
+ unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
+ stats->rx_missed_errors += miss_f;
+ x->rx_missed_cntr += miss_f;
+ }
+ }
+ return;
+}
+
+static int mac100_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
+ struct dma_desc *p, unsigned long ioaddr)
+{
+ int ret = 0;
+ struct net_device_stats *stats = (struct net_device_stats *)data;
+
+ if (unlikely(p->des01.tx.error_summary)) {
+ if (unlikely(p->des01.tx.underflow_error)) {
+ x->tx_underflow++;
+ stats->tx_fifo_errors++;
+ }
+ if (unlikely(p->des01.tx.no_carrier)) {
+ x->tx_carrier++;
+ stats->tx_carrier_errors++;
+ }
+ if (unlikely(p->des01.tx.loss_carrier)) {
+ x->tx_losscarrier++;
+ stats->tx_carrier_errors++;
+ }
+ if (unlikely((p->des01.tx.excessive_deferral) ||
+ (p->des01.tx.excessive_collisions) ||
+ (p->des01.tx.late_collision)))
+ stats->collisions += p->des01.tx.collision_count;
+ ret = -1;
+ }
+ if (unlikely(p->des01.tx.heartbeat_fail)) {
+ x->tx_heartbeat++;
+ stats->tx_heartbeat_errors++;
+ ret = -1;
+ }
+ if (unlikely(p->des01.tx.deferred))
+ x->tx_deferred++;
+
+ return ret;
+}
+
+static int mac100_get_tx_len(struct dma_desc *p)
+{
+ return p->des01.tx.buffer1_size;
+}
+
+/* This function verifies if each incoming frame has some errors
+ * and, if required, updates the multicast statistics.
+ * In case of success, it returns csum_none becasue the device
+ * is not able to compute the csum in HW. */
+static int mac100_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
+ struct dma_desc *p)
+{
+ int ret = csum_none;
+ struct net_device_stats *stats = (struct net_device_stats *)data;
+
+ if (unlikely(p->des01.rx.last_descriptor == 0)) {
+ pr_warning("mac100 Error: Oversized Ethernet "
+ "frame spanned multiple buffers\n");
+ stats->rx_length_errors++;
+ return discard_frame;
+ }
+
+ if (unlikely(p->des01.rx.error_summary)) {
+ if (unlikely(p->des01.rx.descriptor_error))
+ x->rx_desc++;
+ if (unlikely(p->des01.rx.partial_frame_error))
+ x->rx_partial++;
+ if (unlikely(p->des01.rx.run_frame))
+ x->rx_runt++;
+ if (unlikely(p->des01.rx.frame_too_long))
+ x->rx_toolong++;
+ if (unlikely(p->des01.rx.collision)) {
+ x->rx_collision++;
+ stats->collisions++;
+ }
+ if (unlikely(p->des01.rx.crc_error)) {
+ x->rx_crc++;
+ stats->rx_crc_errors++;
+ }
+ ret = discard_frame;
+ }
+ if (unlikely(p->des01.rx.dribbling))
+ ret = discard_frame;
+
+ if (unlikely(p->des01.rx.length_error)) {
+ x->rx_lenght++;
+ ret = discard_frame;
+ }
+ if (unlikely(p->des01.rx.mii_error)) {
+ x->rx_mii++;
+ ret = discard_frame;
+ }
+ if (p->des01.rx.multicast_frame) {
+ x->rx_multicast++;
+ stats->multicast++;
+ }
+ return ret;
+}
+
+static void mac100_irq_status(unsigned long ioaddr)
+{
+ return;
+}
+
+static void mac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
+ unsigned int reg_n)
+{
+ stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
+}
+
+static void mac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
+ unsigned int reg_n)
+{
+ stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
+}
+
+static void mac100_set_filter(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ u32 value = readl(ioaddr + MAC_CONTROL);
+
+ if (dev->flags & IFF_PROMISC) {
+ value |= MAC_CONTROL_PR;
+ value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
+ MAC_CONTROL_HP);
+ } else if ((dev->mc_count > HASH_TABLE_SIZE)
+ || (dev->flags & IFF_ALLMULTI)) {
+ value |= MAC_CONTROL_PM;
+ value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
+ writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
+ writel(0xffffffff, ioaddr + MAC_HASH_LOW);
+ } else if (dev->mc_count == 0) { /* no multicast */
+ value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
+ MAC_CONTROL_HO | MAC_CONTROL_HP);
+ } else {
+ int i;
+ u32 mc_filter[2];
+ struct dev_mc_list *mclist;
+
+ /* Perfect filter mode for physical address and Hash
+ filter for multicast */
+ value |= MAC_CONTROL_HP;
+ value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF
+ | MAC_CONTROL_HO);
+
+ memset(mc_filter, 0, sizeof(mc_filter));
+ for (i = 0, mclist = dev->mc_list;
+ mclist && i < dev->mc_count; i++, mclist = mclist->next) {
+ /* The upper 6 bits of the calculated CRC are used to
+ * index the contens of the hash table */
+ int bit_nr =
+ ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+ /* The most significant bit determines the register to
+ * use (H/L) while the other 5 bits determine the bit
+ * within the register. */
+ mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
+ }
+ writel(mc_filter[0], ioaddr + MAC_HASH_LOW);
+ writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);
+ }
+
+ writel(value, ioaddr + MAC_CONTROL);
+
+ DBG(KERN_INFO "%s: CTRL reg: 0x%08x Hash regs: "
+ "HI 0x%08x, LO 0x%08x\n",
+ __func__, readl(ioaddr + MAC_CONTROL),
+ readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
+ return;
+}
+
+static void mac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
+ unsigned int fc, unsigned int pause_time)
+{
+ unsigned int flow = MAC_FLOW_CTRL_ENABLE;
+
+ if (duplex)
+ flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);
+ writel(flow, ioaddr + MAC_FLOW_CTRL);
+
+ return;
+}
+
+/* No PMT module supported in our SoC for the Ethernet Controller. */
+static void mac100_pmt(unsigned long ioaddr, unsigned long mode)
+{
+ return;
+}
+
+static void mac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
+ int disable_rx_ic)
+{
+ int i;
+ for (i = 0; i < ring_size; i++) {
+ p->des01.rx.own = 1;
+ p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
+ if (i == ring_size - 1)
+ p->des01.rx.end_ring = 1;
+ if (disable_rx_ic)
+ p->des01.rx.disable_ic = 1;
+ p++;
+ }
+ return;
+}
+
+static void mac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
+{
+ int i;
+ for (i = 0; i < ring_size; i++) {
+ p->des01.tx.own = 0;
+ if (i == ring_size - 1)
+ p->des01.tx.end_ring = 1;
+ p++;
+ }
+ return;
+}
+
+static int mac100_get_tx_owner(struct dma_desc *p)
+{
+ return p->des01.tx.own;
+}
+
+static int mac100_get_rx_owner(struct dma_desc *p)
+{
+ return p->des01.rx.own;
+}
+
+static void mac100_set_tx_owner(struct dma_desc *p)
+{
+ p->des01.tx.own = 1;
+}
+
+static void mac100_set_rx_owner(struct dma_desc *p)
+{
+ p->des01.rx.own = 1;
+}
+
+static int mac100_get_tx_ls(struct dma_desc *p)
+{
+ return p->des01.tx.last_segment;
+}
+
+static void mac100_release_tx_desc(struct dma_desc *p)
+{
+ int ter = p->des01.tx.end_ring;
+
+ /* clean field used within the xmit */
+ p->des01.tx.first_segment = 0;
+ p->des01.tx.last_segment = 0;
+ p->des01.tx.buffer1_size = 0;
+
+ /* clean status reported */
+ p->des01.tx.error_summary = 0;
+ p->des01.tx.underflow_error = 0;
+ p->des01.tx.no_carrier = 0;
+ p->des01.tx.loss_carrier = 0;
+ p->des01.tx.excessive_deferral = 0;
+ p->des01.tx.excessive_collisions = 0;
+ p->des01.tx.late_collision = 0;
+ p->des01.tx.heartbeat_fail = 0;
+ p->des01.tx.deferred = 0;
+
+ /* set termination field */
+ p->des01.tx.end_ring = ter;
+
+ return;
+}
+
+static void mac100_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
+ int csum_flag)
+{
+ p->des01.tx.first_segment = is_fs;
+ p->des01.tx.buffer1_size = len;
+}
+
+static void mac100_clear_tx_ic(struct dma_desc *p)
+{
+ p->des01.tx.interrupt = 0;
+}
+
+static void mac100_close_tx_desc(struct dma_desc *p)
+{
+ p->des01.tx.last_segment = 1;
+ p->des01.tx.interrupt = 1;
+}
+
+static int mac100_get_rx_frame_len(struct dma_desc *p)
+{
+ return p->des01.rx.frame_length;
+}
+
+struct stmmac_ops mac100_driver = {
+ .core_init = mac100_core_init,
+ .dump_mac_regs = mac100_dump_mac_regs,
+ .dma_init = mac100_dma_init,
+ .dump_dma_regs = mac100_dump_dma_regs,
+ .dma_mode = mac100_dma_operation_mode,
+ .dma_diagnostic_fr = mac100_dma_diagnostic_fr,
+ .tx_status = mac100_get_tx_frame_status,
+ .rx_status = mac100_get_rx_frame_status,
+ .get_tx_len = mac100_get_tx_len,
+ .set_filter = mac100_set_filter,
+ .flow_ctrl = mac100_flow_ctrl,
+ .pmt = mac100_pmt,
+ .init_rx_desc = mac100_init_rx_desc,
+ .init_tx_desc = mac100_init_tx_desc,
+ .get_tx_owner = mac100_get_tx_owner,
+ .get_rx_owner = mac100_get_rx_owner,
+ .release_tx_desc = mac100_release_tx_desc,
+ .prepare_tx_desc = mac100_prepare_tx_desc,
+ .clear_tx_ic = mac100_clear_tx_ic,
+ .close_tx_desc = mac100_close_tx_desc,
+ .get_tx_ls = mac100_get_tx_ls,
+ .set_tx_owner = mac100_set_tx_owner,
+ .set_rx_owner = mac100_set_rx_owner,
+ .get_rx_frame_len = mac100_get_rx_frame_len,
+ .host_irq_status = mac100_irq_status,
+ .set_umac_addr = mac100_set_umac_addr,
+ .get_umac_addr = mac100_get_umac_addr,
+};
+
+struct mac_device_info *mac100_setup(unsigned long ioaddr)
+{
+ struct mac_device_info *mac;
+
+ mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
+
+ pr_info("\tMAC 10/100\n");
+
+ mac->ops = &mac100_driver;
+ mac->hw.pmt = PMT_NOT_SUPPORTED;
+ mac->hw.link.port = MAC_CONTROL_PS;
+ mac->hw.link.duplex = MAC_CONTROL_F;
+ mac->hw.link.speed = 0;
+ mac->hw.mii.addr = MAC_MII_ADDR;
+ mac->hw.mii.data = MAC_MII_DATA;
+
+ return mac;
+}
diff --git a/drivers/net/stmmac/mac100.h b/drivers/net/stmmac/mac100.h
new file mode 100644
index 000000000000..0f8f110d004a
--- /dev/null
+++ b/drivers/net/stmmac/mac100.h
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ MAC 10/100 Header File
+
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+/*----------------------------------------------------------------------------
+ * MAC BLOCK defines
+ *---------------------------------------------------------------------------*/
+/* MAC CSR offset */
+#define MAC_CONTROL 0x00000000 /* MAC Control */
+#define MAC_ADDR_HIGH 0x00000004 /* MAC Address High */
+#define MAC_ADDR_LOW 0x00000008 /* MAC Address Low */
+#define MAC_HASH_HIGH 0x0000000c /* Multicast Hash Table High */
+#define MAC_HASH_LOW 0x00000010 /* Multicast Hash Table Low */
+#define MAC_MII_ADDR 0x00000014 /* MII Address */
+#define MAC_MII_DATA 0x00000018 /* MII Data */
+#define MAC_FLOW_CTRL 0x0000001c /* Flow Control */
+#define MAC_VLAN1 0x00000020 /* VLAN1 Tag */
+#define MAC_VLAN2 0x00000024 /* VLAN2 Tag */
+
+/* MAC CTRL defines */
+#define MAC_CONTROL_RA 0x80000000 /* Receive All Mode */
+#define MAC_CONTROL_BLE 0x40000000 /* Endian Mode */
+#define MAC_CONTROL_HBD 0x10000000 /* Heartbeat Disable */
+#define MAC_CONTROL_PS 0x08000000 /* Port Select */
+#define MAC_CONTROL_DRO 0x00800000 /* Disable Receive Own */
+#define MAC_CONTROL_EXT_LOOPBACK 0x00400000 /* Reserved (ext loopback?) */
+#define MAC_CONTROL_OM 0x00200000 /* Loopback Operating Mode */
+#define MAC_CONTROL_F 0x00100000 /* Full Duplex Mode */
+#define MAC_CONTROL_PM 0x00080000 /* Pass All Multicast */
+#define MAC_CONTROL_PR 0x00040000 /* Promiscuous Mode */
+#define MAC_CONTROL_IF 0x00020000 /* Inverse Filtering */
+#define MAC_CONTROL_PB 0x00010000 /* Pass Bad Frames */
+#define MAC_CONTROL_HO 0x00008000 /* Hash Only Filtering Mode */
+#define MAC_CONTROL_HP 0x00002000 /* Hash/Perfect Filtering Mode */
+#define MAC_CONTROL_LCC 0x00001000 /* Late Collision Control */
+#define MAC_CONTROL_DBF 0x00000800 /* Disable Broadcast Frames */
+#define MAC_CONTROL_DRTY 0x00000400 /* Disable Retry */
+#define MAC_CONTROL_ASTP 0x00000100 /* Automatic Pad Stripping */
+#define MAC_CONTROL_BOLMT_10 0x00000000 /* Back Off Limit 10 */
+#define MAC_CONTROL_BOLMT_8 0x00000040 /* Back Off Limit 8 */
+#define MAC_CONTROL_BOLMT_4 0x00000080 /* Back Off Limit 4 */
+#define MAC_CONTROL_BOLMT_1 0x000000c0 /* Back Off Limit 1 */
+#define MAC_CONTROL_DC 0x00000020 /* Deferral Check */
+#define MAC_CONTROL_TE 0x00000008 /* Transmitter Enable */
+#define MAC_CONTROL_RE 0x00000004 /* Receiver Enable */
+
+#define MAC_CORE_INIT (MAC_CONTROL_HBD | MAC_CONTROL_ASTP)
+
+/* MAC FLOW CTRL defines */
+#define MAC_FLOW_CTRL_PT_MASK 0xffff0000 /* Pause Time Mask */
+#define MAC_FLOW_CTRL_PT_SHIFT 16
+#define MAC_FLOW_CTRL_PASS 0x00000004 /* Pass Control Frames */
+#define MAC_FLOW_CTRL_ENABLE 0x00000002 /* Flow Control Enable */
+#define MAC_FLOW_CTRL_PAUSE 0x00000001 /* Flow Control Busy ... */
+
+/* MII ADDR defines */
+#define MAC_MII_ADDR_WRITE 0x00000002 /* MII Write */
+#define MAC_MII_ADDR_BUSY 0x00000001 /* MII Busy */
+
+/*----------------------------------------------------------------------------
+ * DMA BLOCK defines
+ *---------------------------------------------------------------------------*/
+
+/* DMA Bus Mode register defines */
+#define DMA_BUS_MODE_DBO 0x00100000 /* Descriptor Byte Ordering */
+#define DMA_BUS_MODE_BLE 0x00000080 /* Big Endian/Little Endian */
+#define DMA_BUS_MODE_PBL_MASK 0x00003f00 /* Programmable Burst Len */
+#define DMA_BUS_MODE_PBL_SHIFT 8
+#define DMA_BUS_MODE_DSL_MASK 0x0000007c /* Descriptor Skip Length */
+#define DMA_BUS_MODE_DSL_SHIFT 2 /* (in DWORDS) */
+#define DMA_BUS_MODE_BAR_BUS 0x00000002 /* Bar-Bus Arbitration */
+#define DMA_BUS_MODE_SFT_RESET 0x00000001 /* Software Reset */
+#define DMA_BUS_MODE_DEFAULT 0x00000000
+
+/* DMA Control register defines */
+#define DMA_CONTROL_SF 0x00200000 /* Store And Forward */
+
+/* Transmit Threshold Control */
+enum ttc_control {
+ DMA_CONTROL_TTC_DEFAULT = 0x00000000, /* Threshold is 32 DWORDS */
+ DMA_CONTROL_TTC_64 = 0x00004000, /* Threshold is 64 DWORDS */
+ DMA_CONTROL_TTC_128 = 0x00008000, /* Threshold is 128 DWORDS */
+ DMA_CONTROL_TTC_256 = 0x0000c000, /* Threshold is 256 DWORDS */
+ DMA_CONTROL_TTC_18 = 0x00400000, /* Threshold is 18 DWORDS */
+ DMA_CONTROL_TTC_24 = 0x00404000, /* Threshold is 24 DWORDS */
+ DMA_CONTROL_TTC_32 = 0x00408000, /* Threshold is 32 DWORDS */
+ DMA_CONTROL_TTC_40 = 0x0040c000, /* Threshold is 40 DWORDS */
+ DMA_CONTROL_SE = 0x00000008, /* Stop On Empty */
+ DMA_CONTROL_OSF = 0x00000004, /* Operate On 2nd Frame */
+};
+
+/* STMAC110 DMA Missed Frame Counter register defines */
+#define DMA_MISSED_FRAME_OVE 0x10000000 /* FIFO Overflow Overflow */
+#define DMA_MISSED_FRAME_OVE_CNTR 0x0ffe0000 /* Overflow Frame Counter */
+#define DMA_MISSED_FRAME_OVE_M 0x00010000 /* Missed Frame Overflow */
+#define DMA_MISSED_FRAME_M_CNTR 0x0000ffff /* Missed Frame Couinter */
diff --git a/drivers/net/stmmac/stmmac.h b/drivers/net/stmmac/stmmac.h
new file mode 100644
index 000000000000..6d2eae3040e5
--- /dev/null
+++ b/drivers/net/stmmac/stmmac.h
@@ -0,0 +1,98 @@
+/*******************************************************************************
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#define DRV_MODULE_VERSION "Oct_09"
+
+#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
+#define STMMAC_VLAN_TAG_USED
+#include <linux/if_vlan.h>
+#endif
+
+#include "common.h"
+#ifdef CONFIG_STMMAC_TIMER
+#include "stmmac_timer.h"
+#endif
+
+struct stmmac_priv {
+ /* Frequently used values are kept adjacent for cache effect */
+ struct dma_desc *dma_tx ____cacheline_aligned;
+ dma_addr_t dma_tx_phy;
+ struct sk_buff **tx_skbuff;
+ unsigned int cur_tx;
+ unsigned int dirty_tx;
+ unsigned int dma_tx_size;
+ int tx_coe;
+ int tx_coalesce;
+
+ struct dma_desc *dma_rx ;
+ unsigned int cur_rx;
+ unsigned int dirty_rx;
+ struct sk_buff **rx_skbuff;
+ dma_addr_t *rx_skbuff_dma;
+ struct sk_buff_head rx_recycle;
+
+ struct net_device *dev;
+ int is_gmac;
+ dma_addr_t dma_rx_phy;
+ unsigned int dma_rx_size;
+ int rx_csum;
+ unsigned int dma_buf_sz;
+ struct device *device;
+ struct mac_device_info *mac_type;
+
+ struct stmmac_extra_stats xstats;
+ struct napi_struct napi;
+
+ phy_interface_t phy_interface;
+ int pbl;
+ int bus_id;
+ int phy_addr;
+ int phy_mask;
+ int (*phy_reset) (void *priv);
+ void (*fix_mac_speed) (void *priv, unsigned int speed);
+ void *bsp_priv;
+
+ int phy_irq;
+ struct phy_device *phydev;
+ int oldlink;
+ int speed;
+ int oldduplex;
+ unsigned int flow_ctrl;
+ unsigned int pause;
+ struct mii_bus *mii;
+
+ u32 msg_enable;
+ spinlock_t lock;
+ int wolopts;
+ int wolenabled;
+ int shutdown;
+#ifdef CONFIG_STMMAC_TIMER
+ struct stmmac_timer *tm;
+#endif
+#ifdef STMMAC_VLAN_TAG_USED
+ struct vlan_group *vlgrp;
+#endif
+};
+
+extern int stmmac_mdio_unregister(struct net_device *ndev);
+extern int stmmac_mdio_register(struct net_device *ndev);
+extern void stmmac_set_ethtool_ops(struct net_device *netdev);
diff --git a/drivers/net/stmmac/stmmac_ethtool.c b/drivers/net/stmmac/stmmac_ethtool.c
new file mode 100644
index 000000000000..694ebe6a0758
--- /dev/null
+++ b/drivers/net/stmmac/stmmac_ethtool.c
@@ -0,0 +1,395 @@
+/*******************************************************************************
+ STMMAC Ethtool support
+
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#include "stmmac.h"
+
+#define REG_SPACE_SIZE 0x1054
+#define MAC100_ETHTOOL_NAME "st_mac100"
+#define GMAC_ETHTOOL_NAME "st_gmac"
+
+struct stmmac_stats {
+ char stat_string[ETH_GSTRING_LEN];
+ int sizeof_stat;
+ int stat_offset;
+};
+
+#define STMMAC_STAT(m) \
+ { #m, FIELD_SIZEOF(struct stmmac_extra_stats, m), \
+ offsetof(struct stmmac_priv, xstats.m)}
+
+static const struct stmmac_stats stmmac_gstrings_stats[] = {
+ STMMAC_STAT(tx_underflow),
+ STMMAC_STAT(tx_carrier),
+ STMMAC_STAT(tx_losscarrier),
+ STMMAC_STAT(tx_heartbeat),
+ STMMAC_STAT(tx_deferred),
+ STMMAC_STAT(tx_vlan),
+ STMMAC_STAT(rx_vlan),
+ STMMAC_STAT(tx_jabber),
+ STMMAC_STAT(tx_frame_flushed),
+ STMMAC_STAT(tx_payload_error),
+ STMMAC_STAT(tx_ip_header_error),
+ STMMAC_STAT(rx_desc),
+ STMMAC_STAT(rx_partial),
+ STMMAC_STAT(rx_runt),
+ STMMAC_STAT(rx_toolong),
+ STMMAC_STAT(rx_collision),
+ STMMAC_STAT(rx_crc),
+ STMMAC_STAT(rx_lenght),
+ STMMAC_STAT(rx_mii),
+ STMMAC_STAT(rx_multicast),
+ STMMAC_STAT(rx_gmac_overflow),
+ STMMAC_STAT(rx_watchdog),
+ STMMAC_STAT(da_rx_filter_fail),
+ STMMAC_STAT(sa_rx_filter_fail),
+ STMMAC_STAT(rx_missed_cntr),
+ STMMAC_STAT(rx_overflow_cntr),
+ STMMAC_STAT(tx_undeflow_irq),
+ STMMAC_STAT(tx_process_stopped_irq),
+ STMMAC_STAT(tx_jabber_irq),
+ STMMAC_STAT(rx_overflow_irq),
+ STMMAC_STAT(rx_buf_unav_irq),
+ STMMAC_STAT(rx_process_stopped_irq),
+ STMMAC_STAT(rx_watchdog_irq),
+ STMMAC_STAT(tx_early_irq),
+ STMMAC_STAT(fatal_bus_error_irq),
+ STMMAC_STAT(threshold),
+ STMMAC_STAT(tx_pkt_n),
+ STMMAC_STAT(rx_pkt_n),
+ STMMAC_STAT(poll_n),
+ STMMAC_STAT(sched_timer_n),
+ STMMAC_STAT(normal_irq_n),
+};
+#define STMMAC_STATS_LEN ARRAY_SIZE(stmmac_gstrings_stats)
+
+void stmmac_ethtool_getdrvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ if (!priv->is_gmac)
+ strcpy(info->driver, MAC100_ETHTOOL_NAME);
+ else
+ strcpy(info->driver, GMAC_ETHTOOL_NAME);
+
+ strcpy(info->version, DRV_MODULE_VERSION);
+ info->fw_version[0] = '\0';
+ info->n_stats = STMMAC_STATS_LEN;
+ return;
+}
+
+int stmmac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ struct phy_device *phy = priv->phydev;
+ int rc;
+ if (phy == NULL) {
+ pr_err("%s: %s: PHY is not registered\n",
+ __func__, dev->name);
+ return -ENODEV;
+ }
+ if (!netif_running(dev)) {
+ pr_err("%s: interface is disabled: we cannot track "
+ "link speed / duplex setting\n", dev->name);
+ return -EBUSY;
+ }
+ cmd->transceiver = XCVR_INTERNAL;
+ spin_lock_irq(&priv->lock);
+ rc = phy_ethtool_gset(phy, cmd);
+ spin_unlock_irq(&priv->lock);
+ return rc;
+}
+
+int stmmac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ struct phy_device *phy = priv->phydev;
+ int rc;
+
+ spin_lock(&priv->lock);
+ rc = phy_ethtool_sset(phy, cmd);
+ spin_unlock(&priv->lock);
+
+ return rc;
+}
+
+u32 stmmac_ethtool_getmsglevel(struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ return priv->msg_enable;
+}
+
+void stmmac_ethtool_setmsglevel(struct net_device *dev, u32 level)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ priv->msg_enable = level;
+
+}
+
+int stmmac_check_if_running(struct net_device *dev)
+{
+ if (!netif_running(dev))
+ return -EBUSY;
+ return 0;
+}
+
+int stmmac_ethtool_get_regs_len(struct net_device *dev)
+{
+ return REG_SPACE_SIZE;
+}
+
+void stmmac_ethtool_gregs(struct net_device *dev,
+ struct ethtool_regs *regs, void *space)
+{
+ int i;
+ u32 *reg_space = (u32 *) space;
+
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ memset(reg_space, 0x0, REG_SPACE_SIZE);
+
+ if (!priv->is_gmac) {
+ /* MAC registers */
+ for (i = 0; i < 12; i++)
+ reg_space[i] = readl(dev->base_addr + (i * 4));
+ /* DMA registers */
+ for (i = 0; i < 9; i++)
+ reg_space[i + 12] =
+ readl(dev->base_addr + (DMA_BUS_MODE + (i * 4)));
+ reg_space[22] = readl(dev->base_addr + DMA_CUR_TX_BUF_ADDR);
+ reg_space[23] = readl(dev->base_addr + DMA_CUR_RX_BUF_ADDR);
+ } else {
+ /* MAC registers */
+ for (i = 0; i < 55; i++)
+ reg_space[i] = readl(dev->base_addr + (i * 4));
+ /* DMA registers */
+ for (i = 0; i < 22; i++)
+ reg_space[i + 55] =
+ readl(dev->base_addr + (DMA_BUS_MODE + (i * 4)));
+ }
+
+ return;
+}
+
+int stmmac_ethtool_set_tx_csum(struct net_device *netdev, u32 data)
+{
+ if (data)
+ netdev->features |= NETIF_F_HW_CSUM;
+ else
+ netdev->features &= ~NETIF_F_HW_CSUM;
+
+ return 0;
+}
+
+u32 stmmac_ethtool_get_rx_csum(struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ return priv->rx_csum;
+}
+
+static void
+stmmac_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct stmmac_priv *priv = netdev_priv(netdev);
+
+ spin_lock(&priv->lock);
+
+ pause->rx_pause = 0;
+ pause->tx_pause = 0;
+ pause->autoneg = priv->phydev->autoneg;
+
+ if (priv->flow_ctrl & FLOW_RX)
+ pause->rx_pause = 1;
+ if (priv->flow_ctrl & FLOW_TX)
+ pause->tx_pause = 1;
+
+ spin_unlock(&priv->lock);
+ return;
+}
+
+static int
+stmmac_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pause)
+{
+ struct stmmac_priv *priv = netdev_priv(netdev);
+ struct phy_device *phy = priv->phydev;
+ int new_pause = FLOW_OFF;
+ int ret = 0;
+
+ spin_lock(&priv->lock);
+
+ if (pause->rx_pause)
+ new_pause |= FLOW_RX;
+ if (pause->tx_pause)
+ new_pause |= FLOW_TX;
+
+ priv->flow_ctrl = new_pause;
+
+ if (phy->autoneg) {
+ if (netif_running(netdev)) {
+ struct ethtool_cmd cmd;
+ /* auto-negotiation automatically restarted */
+ cmd.cmd = ETHTOOL_NWAY_RST;
+ cmd.supported = phy->supported;
+ cmd.advertising = phy->advertising;
+ cmd.autoneg = phy->autoneg;
+ cmd.speed = phy->speed;
+ cmd.duplex = phy->duplex;
+ cmd.phy_address = phy->addr;
+ ret = phy_ethtool_sset(phy, &cmd);
+ }
+ } else {
+ unsigned long ioaddr = netdev->base_addr;
+ priv->mac_type->ops->flow_ctrl(ioaddr, phy->duplex,
+ priv->flow_ctrl, priv->pause);
+ }
+ spin_unlock(&priv->lock);
+ return ret;
+}
+
+static void stmmac_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *dummy, u64 *data)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ int i;
+
+ /* Update HW stats if supported */
+ priv->mac_type->ops->dma_diagnostic_fr(&dev->stats, &priv->xstats,
+ ioaddr);
+
+ for (i = 0; i < STMMAC_STATS_LEN; i++) {
+ char *p = (char *)priv + stmmac_gstrings_stats[i].stat_offset;
+ data[i] = (stmmac_gstrings_stats[i].sizeof_stat ==
+ sizeof(u64)) ? (*(u64 *)p) : (*(u32 *)p);
+ }
+
+ return;
+}
+
+static int stmmac_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return STMMAC_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void stmmac_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ int i;
+ u8 *p = data;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < STMMAC_STATS_LEN; i++) {
+ memcpy(p, stmmac_gstrings_stats[i].stat_string,
+ ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+ return;
+}
+
+/* Currently only support WOL through Magic packet. */
+static void stmmac_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ spin_lock_irq(&priv->lock);
+ if (priv->wolenabled == PMT_SUPPORTED) {
+ wol->supported = WAKE_MAGIC;
+ wol->wolopts = priv->wolopts;
+ }
+ spin_unlock_irq(&priv->lock);
+}
+
+static int stmmac_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ u32 support = WAKE_MAGIC;
+
+ if (priv->wolenabled == PMT_NOT_SUPPORTED)
+ return -EINVAL;
+
+ if (wol->wolopts & ~support)
+ return -EINVAL;
+
+ if (wol->wolopts == 0)
+ device_set_wakeup_enable(priv->device, 0);
+ else
+ device_set_wakeup_enable(priv->device, 1);
+
+ spin_lock_irq(&priv->lock);
+ priv->wolopts = wol->wolopts;
+ spin_unlock_irq(&priv->lock);
+
+ return 0;
+}
+
+static struct ethtool_ops stmmac_ethtool_ops = {
+ .begin = stmmac_check_if_running,
+ .get_drvinfo = stmmac_ethtool_getdrvinfo,
+ .get_settings = stmmac_ethtool_getsettings,
+ .set_settings = stmmac_ethtool_setsettings,
+ .get_msglevel = stmmac_ethtool_getmsglevel,
+ .set_msglevel = stmmac_ethtool_setmsglevel,
+ .get_regs = stmmac_ethtool_gregs,
+ .get_regs_len = stmmac_ethtool_get_regs_len,
+ .get_link = ethtool_op_get_link,
+ .get_rx_csum = stmmac_ethtool_get_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = stmmac_ethtool_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_pauseparam = stmmac_get_pauseparam,
+ .set_pauseparam = stmmac_set_pauseparam,
+ .get_ethtool_stats = stmmac_get_ethtool_stats,
+ .get_strings = stmmac_get_strings,
+ .get_wol = stmmac_get_wol,
+ .set_wol = stmmac_set_wol,
+ .get_sset_count = stmmac_get_sset_count,
+#ifdef NETIF_F_TSO
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+#endif
+};
+
+void stmmac_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &stmmac_ethtool_ops);
+}
diff --git a/drivers/net/stmmac/stmmac_main.c b/drivers/net/stmmac/stmmac_main.c
new file mode 100644
index 000000000000..c2f14dc9ba28
--- /dev/null
+++ b/drivers/net/stmmac/stmmac_main.c
@@ -0,0 +1,2204 @@
+/*******************************************************************************
+ This is the driver for the ST MAC 10/100/1000 on-chip Ethernet controllers.
+ ST Ethernet IPs are built around a Synopsys IP Core.
+
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+
+ Documentation available at:
+ http://www.stlinux.com
+ Support available at:
+ https://bugzilla.stlinux.com/
+*******************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/skbuff.h>
+#include <linux/ethtool.h>
+#include <linux/if_ether.h>
+#include <linux/crc32.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+#include <linux/if_vlan.h>
+#include <linux/dma-mapping.h>
+#include <linux/stm/soc.h>
+#include "stmmac.h"
+
+#define STMMAC_RESOURCE_NAME "stmmaceth"
+#define PHY_RESOURCE_NAME "stmmacphy"
+
+#undef STMMAC_DEBUG
+/*#define STMMAC_DEBUG*/
+#ifdef STMMAC_DEBUG
+#define DBG(nlevel, klevel, fmt, args...) \
+ ((void)(netif_msg_##nlevel(priv) && \
+ printk(KERN_##klevel fmt, ## args)))
+#else
+#define DBG(nlevel, klevel, fmt, args...) do { } while (0)
+#endif
+
+#undef STMMAC_RX_DEBUG
+/*#define STMMAC_RX_DEBUG*/
+#ifdef STMMAC_RX_DEBUG
+#define RX_DBG(fmt, args...) printk(fmt, ## args)
+#else
+#define RX_DBG(fmt, args...) do { } while (0)
+#endif
+
+#undef STMMAC_XMIT_DEBUG
+/*#define STMMAC_XMIT_DEBUG*/
+#ifdef STMMAC_TX_DEBUG
+#define TX_DBG(fmt, args...) printk(fmt, ## args)
+#else
+#define TX_DBG(fmt, args...) do { } while (0)
+#endif
+
+#define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x)
+#define JUMBO_LEN 9000
+
+/* Module parameters */
+#define TX_TIMEO 5000 /* default 5 seconds */
+static int watchdog = TX_TIMEO;
+module_param(watchdog, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(watchdog, "Transmit timeout in milliseconds");
+
+static int debug = -1; /* -1: default, 0: no output, 16: all */
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Message Level (0: no output, 16: all)");
+
+static int phyaddr = -1;
+module_param(phyaddr, int, S_IRUGO);
+MODULE_PARM_DESC(phyaddr, "Physical device address");
+
+#define DMA_TX_SIZE 256
+static int dma_txsize = DMA_TX_SIZE;
+module_param(dma_txsize, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dma_txsize, "Number of descriptors in the TX list");
+
+#define DMA_RX_SIZE 256
+static int dma_rxsize = DMA_RX_SIZE;
+module_param(dma_rxsize, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dma_rxsize, "Number of descriptors in the RX list");
+
+static int flow_ctrl = FLOW_OFF;
+module_param(flow_ctrl, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(flow_ctrl, "Flow control ability [on/off]");
+
+static int pause = PAUSE_TIME;
+module_param(pause, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(pause, "Flow Control Pause Time");
+
+#define TC_DEFAULT 64
+static int tc = TC_DEFAULT;
+module_param(tc, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(tc, "DMA threshold control value");
+
+#define RX_NO_COALESCE 1 /* Always interrupt on completion */
+#define TX_NO_COALESCE -1 /* No moderation by default */
+
+/* Pay attention to tune this parameter; take care of both
+ * hardware capability and network stabitily/performance impact.
+ * Many tests showed that ~4ms latency seems to be good enough. */
+#ifdef CONFIG_STMMAC_TIMER
+#define DEFAULT_PERIODIC_RATE 256
+static int tmrate = DEFAULT_PERIODIC_RATE;
+module_param(tmrate, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(tmrate, "External timer freq. (default: 256Hz)");
+#endif
+
+#define DMA_BUFFER_SIZE BUF_SIZE_2KiB
+static int buf_sz = DMA_BUFFER_SIZE;
+module_param(buf_sz, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(buf_sz, "DMA buffer size");
+
+/* In case of Giga ETH, we can enable/disable the COE for the
+ * transmit HW checksum computation.
+ * Note that, if tx csum is off in HW, SG will be still supported. */
+static int tx_coe = HW_CSUM;
+module_param(tx_coe, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(tx_coe, "GMAC COE type 2 [on/off]");
+
+static const u32 default_msg_level = (NETIF_MSG_DRV | NETIF_MSG_PROBE |
+ NETIF_MSG_LINK | NETIF_MSG_IFUP |
+ NETIF_MSG_IFDOWN | NETIF_MSG_TIMER);
+
+static irqreturn_t stmmac_interrupt(int irq, void *dev_id);
+static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev);
+
+/**
+ * stmmac_verify_args - verify the driver parameters.
+ * Description: it verifies if some wrong parameter is passed to the driver.
+ * Note that wrong parameters are replaced with the default values.
+ */
+static void stmmac_verify_args(void)
+{
+ if (unlikely(watchdog < 0))
+ watchdog = TX_TIMEO;
+ if (unlikely(dma_rxsize < 0))
+ dma_rxsize = DMA_RX_SIZE;
+ if (unlikely(dma_txsize < 0))
+ dma_txsize = DMA_TX_SIZE;
+ if (unlikely((buf_sz < DMA_BUFFER_SIZE) || (buf_sz > BUF_SIZE_16KiB)))
+ buf_sz = DMA_BUFFER_SIZE;
+ if (unlikely(flow_ctrl > 1))
+ flow_ctrl = FLOW_AUTO;
+ else if (likely(flow_ctrl < 0))
+ flow_ctrl = FLOW_OFF;
+ if (unlikely((pause < 0) || (pause > 0xffff)))
+ pause = PAUSE_TIME;
+
+ return;
+}
+
+#if defined(STMMAC_XMIT_DEBUG) || defined(STMMAC_RX_DEBUG)
+static void print_pkt(unsigned char *buf, int len)
+{
+ int j;
+ pr_info("len = %d byte, buf addr: 0x%p", len, buf);
+ for (j = 0; j < len; j++) {
+ if ((j % 16) == 0)
+ pr_info("\n %03x:", j);
+ pr_info(" %02x", buf[j]);
+ }
+ pr_info("\n");
+ return;
+}
+#endif
+
+/* minimum number of free TX descriptors required to wake up TX process */
+#define STMMAC_TX_THRESH(x) (x->dma_tx_size/4)
+
+static inline u32 stmmac_tx_avail(struct stmmac_priv *priv)
+{
+ return priv->dirty_tx + priv->dma_tx_size - priv->cur_tx - 1;
+}
+
+/**
+ * stmmac_adjust_link
+ * @dev: net device structure
+ * Description: it adjusts the link parameters.
+ */
+static void stmmac_adjust_link(struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev = priv->phydev;
+ unsigned long ioaddr = dev->base_addr;
+ unsigned long flags;
+ int new_state = 0;
+ unsigned int fc = priv->flow_ctrl, pause_time = priv->pause;
+
+ if (phydev == NULL)
+ return;
+
+ DBG(probe, DEBUG, "stmmac_adjust_link: called. address %d link %d\n",
+ phydev->addr, phydev->link);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (phydev->link) {
+ u32 ctrl = readl(ioaddr + MAC_CTRL_REG);
+
+ /* Now we make sure that we can be in full duplex mode.
+ * If not, we operate in half-duplex mode. */
+ if (phydev->duplex != priv->oldduplex) {
+ new_state = 1;
+ if (!(phydev->duplex))
+ ctrl &= ~priv->mac_type->hw.link.duplex;
+ else
+ ctrl |= priv->mac_type->hw.link.duplex;
+ priv->oldduplex = phydev->duplex;
+ }
+ /* Flow Control operation */
+ if (phydev->pause)
+ priv->mac_type->ops->flow_ctrl(ioaddr, phydev->duplex,
+ fc, pause_time);
+
+ if (phydev->speed != priv->speed) {
+ new_state = 1;
+ switch (phydev->speed) {
+ case 1000:
+ if (likely(priv->is_gmac))
+ ctrl &= ~priv->mac_type->hw.link.port;
+ break;
+ case 100:
+ case 10:
+ if (priv->is_gmac) {
+ ctrl |= priv->mac_type->hw.link.port;
+ if (phydev->speed == SPEED_100) {
+ ctrl |=
+ priv->mac_type->hw.link.
+ speed;
+ } else {
+ ctrl &=
+ ~(priv->mac_type->hw.
+ link.speed);
+ }
+ } else {
+ ctrl &= ~priv->mac_type->hw.link.port;
+ }
+ priv->fix_mac_speed(priv->bsp_priv,
+ phydev->speed);
+ break;
+ default:
+ if (netif_msg_link(priv))
+ pr_warning("%s: Speed (%d) is not 10"
+ " or 100!\n", dev->name, phydev->speed);
+ break;
+ }
+
+ priv->speed = phydev->speed;
+ }
+
+ writel(ctrl, ioaddr + MAC_CTRL_REG);
+
+ if (!priv->oldlink) {
+ new_state = 1;
+ priv->oldlink = 1;
+ }
+ } else if (priv->oldlink) {
+ new_state = 1;
+ priv->oldlink = 0;
+ priv->speed = 0;
+ priv->oldduplex = -1;
+ }
+
+ if (new_state && netif_msg_link(priv))
+ phy_print_status(phydev);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ DBG(probe, DEBUG, "stmmac_adjust_link: exiting\n");
+}
+
+/**
+ * stmmac_init_phy - PHY initialization
+ * @dev: net device structure
+ * Description: it initializes the driver's PHY state, and attaches the PHY
+ * to the mac driver.
+ * Return value:
+ * 0 on success
+ */
+static int stmmac_init_phy(struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ struct phy_device *phydev;
+ char phy_id[BUS_ID_SIZE]; /* PHY to connect */
+ char bus_id[BUS_ID_SIZE];
+
+ priv->oldlink = 0;
+ priv->speed = 0;
+ priv->oldduplex = -1;
+
+ if (priv->phy_addr == -1) {
+ /* We don't have a PHY, so do nothing */
+ return 0;
+ }
+
+ snprintf(bus_id, MII_BUS_ID_SIZE, "%x", priv->bus_id);
+ snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, bus_id, priv->phy_addr);
+ pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id);
+
+ phydev = phy_connect(dev, phy_id, &stmmac_adjust_link, 0,
+ priv->phy_interface);
+
+ if (IS_ERR(phydev)) {
+ pr_err("%s: Could not attach to PHY\n", dev->name);
+ return PTR_ERR(phydev);
+ }
+
+ /*
+ * Broken HW is sometimes missing the pull-up resistor on the
+ * MDIO line, which results in reads to non-existent devices returning
+ * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent
+ * device as well.
+ * Note: phydev->phy_id is the result of reading the UID PHY registers.
+ */
+ if (phydev->phy_id == 0) {
+ phy_disconnect(phydev);
+ return -ENODEV;
+ }
+ pr_debug("stmmac_init_phy: %s: attached to PHY (UID 0x%x)"
+ " Link = %d\n", dev->name, phydev->phy_id, phydev->link);
+
+ priv->phydev = phydev;
+
+ return 0;
+}
+
+static inline void stmmac_mac_enable_rx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + MAC_CTRL_REG);
+ value |= MAC_RNABLE_RX;
+ /* Set the RE (receive enable bit into the MAC CTRL register). */
+ writel(value, ioaddr + MAC_CTRL_REG);
+}
+
+static inline void stmmac_mac_enable_tx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + MAC_CTRL_REG);
+ value |= MAC_ENABLE_TX;
+ /* Set the TE (transmit enable bit into the MAC CTRL register). */
+ writel(value, ioaddr + MAC_CTRL_REG);
+}
+
+static inline void stmmac_mac_disable_rx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + MAC_CTRL_REG);
+ value &= ~MAC_RNABLE_RX;
+ writel(value, ioaddr + MAC_CTRL_REG);
+}
+
+static inline void stmmac_mac_disable_tx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + MAC_CTRL_REG);
+ value &= ~MAC_ENABLE_TX;
+ writel(value, ioaddr + MAC_CTRL_REG);
+}
+
+/**
+ * display_ring
+ * @p: pointer to the ring.
+ * @size: size of the ring.
+ * Description: display all the descriptors within the ring.
+ */
+static void display_ring(struct dma_desc *p, int size)
+{
+ struct tmp_s {
+ u64 a;
+ unsigned int b;
+ unsigned int c;
+ };
+ int i;
+ for (i = 0; i < size; i++) {
+ struct tmp_s *x = (struct tmp_s *)(p + i);
+ pr_info("\t%d [0x%x]: DES0=0x%x DES1=0x%x BUF1=0x%x BUF2=0x%x",
+ i, (unsigned int)virt_to_phys(&p[i]),
+ (unsigned int)(x->a), (unsigned int)((x->a) >> 32),
+ x->b, x->c);
+ pr_info("\n");
+ }
+}
+
+/**
+ * init_dma_desc_rings - init the RX/TX descriptor rings
+ * @dev: net device structure
+ * Description: this function initializes the DMA RX/TX descriptors
+ * and allocates the socket buffers.
+ */
+static void init_dma_desc_rings(struct net_device *dev)
+{
+ int i;
+ struct stmmac_priv *priv = netdev_priv(dev);
+ struct sk_buff *skb;
+ unsigned int txsize = priv->dma_tx_size;
+ unsigned int rxsize = priv->dma_rx_size;
+ unsigned int bfsize = priv->dma_buf_sz;
+ int buff2_needed = 0;
+ int dis_ic = 0;
+
+#ifdef CONFIG_STMMAC_TIMER
+ /* Using Timers disable interrupts on completion for the reception */
+ dis_ic = 1;
+#endif
+ /* Set the Buffer size according to the MTU;
+ * indeed, in case of jumbo we need to bump-up the buffer sizes.
+ */
+ if (unlikely(dev->mtu >= BUF_SIZE_8KiB))
+ bfsize = BUF_SIZE_16KiB;
+ else if (unlikely(dev->mtu >= BUF_SIZE_4KiB))
+ bfsize = BUF_SIZE_8KiB;
+ else if (unlikely(dev->mtu >= BUF_SIZE_2KiB))
+ bfsize = BUF_SIZE_4KiB;
+ else if (unlikely(dev->mtu >= DMA_BUFFER_SIZE))
+ bfsize = BUF_SIZE_2KiB;
+ else
+ bfsize = DMA_BUFFER_SIZE;
+
+ /* If the MTU exceeds 8k so use the second buffer in the chain */
+ if (bfsize >= BUF_SIZE_8KiB)
+ buff2_needed = 1;
+
+ DBG(probe, INFO, "stmmac: txsize %d, rxsize %d, bfsize %d\n",
+ txsize, rxsize, bfsize);
+
+ priv->rx_skbuff_dma = kmalloc(rxsize * sizeof(dma_addr_t), GFP_KERNEL);
+ priv->rx_skbuff =
+ kmalloc(sizeof(struct sk_buff *) * rxsize, GFP_KERNEL);
+ priv->dma_rx =
+ (struct dma_desc *)dma_alloc_coherent(priv->device,
+ rxsize *
+ sizeof(struct dma_desc),
+ &priv->dma_rx_phy,
+ GFP_KERNEL);
+ priv->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * txsize,
+ GFP_KERNEL);
+ priv->dma_tx =
+ (struct dma_desc *)dma_alloc_coherent(priv->device,
+ txsize *
+ sizeof(struct dma_desc),
+ &priv->dma_tx_phy,
+ GFP_KERNEL);
+
+ if ((priv->dma_rx == NULL) || (priv->dma_tx == NULL)) {
+ pr_err("%s:ERROR allocating the DMA Tx/Rx desc\n", __func__);
+ return;
+ }
+
+ DBG(probe, INFO, "stmmac (%s) DMA desc rings: virt addr (Rx %p, "
+ "Tx %p)\n\tDMA phy addr (Rx 0x%08x, Tx 0x%08x)\n",
+ dev->name, priv->dma_rx, priv->dma_tx,
+ (unsigned int)priv->dma_rx_phy, (unsigned int)priv->dma_tx_phy);
+
+ /* RX INITIALIZATION */
+ DBG(probe, INFO, "stmmac: SKB addresses:\n"
+ "skb\t\tskb data\tdma data\n");
+
+ for (i = 0; i < rxsize; i++) {
+ struct dma_desc *p = priv->dma_rx + i;
+
+ skb = netdev_alloc_skb_ip_align(dev, bfsize);
+ if (unlikely(skb == NULL)) {
+ pr_err("%s: Rx init fails; skb is NULL\n", __func__);
+ break;
+ }
+ priv->rx_skbuff[i] = skb;
+ priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
+ bfsize, DMA_FROM_DEVICE);
+
+ p->des2 = priv->rx_skbuff_dma[i];
+ if (unlikely(buff2_needed))
+ p->des3 = p->des2 + BUF_SIZE_8KiB;
+ DBG(probe, INFO, "[%p]\t[%p]\t[%x]\n", priv->rx_skbuff[i],
+ priv->rx_skbuff[i]->data, priv->rx_skbuff_dma[i]);
+ }
+ priv->cur_rx = 0;
+ priv->dirty_rx = (unsigned int)(i - rxsize);
+ priv->dma_buf_sz = bfsize;
+ buf_sz = bfsize;
+
+ /* TX INITIALIZATION */
+ for (i = 0; i < txsize; i++) {
+ priv->tx_skbuff[i] = NULL;
+ priv->dma_tx[i].des2 = 0;
+ }
+ priv->dirty_tx = 0;
+ priv->cur_tx = 0;
+
+ /* Clear the Rx/Tx descriptors */
+ priv->mac_type->ops->init_rx_desc(priv->dma_rx, rxsize, dis_ic);
+ priv->mac_type->ops->init_tx_desc(priv->dma_tx, txsize);
+
+ if (netif_msg_hw(priv)) {
+ pr_info("RX descriptor ring:\n");
+ display_ring(priv->dma_rx, rxsize);
+ pr_info("TX descriptor ring:\n");
+ display_ring(priv->dma_tx, txsize);
+ }
+ return;
+}
+
+static void dma_free_rx_skbufs(struct stmmac_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->dma_rx_size; i++) {
+ if (priv->rx_skbuff[i]) {
+ dma_unmap_single(priv->device, priv->rx_skbuff_dma[i],
+ priv->dma_buf_sz, DMA_FROM_DEVICE);
+ dev_kfree_skb_any(priv->rx_skbuff[i]);
+ }
+ priv->rx_skbuff[i] = NULL;
+ }
+ return;
+}
+
+static void dma_free_tx_skbufs(struct stmmac_priv *priv)
+{
+ int i;
+
+ for (i = 0; i < priv->dma_tx_size; i++) {
+ if (priv->tx_skbuff[i] != NULL) {
+ struct dma_desc *p = priv->dma_tx + i;
+ if (p->des2)
+ dma_unmap_single(priv->device, p->des2,
+ priv->mac_type->ops->get_tx_len(p),
+ DMA_TO_DEVICE);
+ dev_kfree_skb_any(priv->tx_skbuff[i]);
+ priv->tx_skbuff[i] = NULL;
+ }
+ }
+ return;
+}
+
+static void free_dma_desc_resources(struct stmmac_priv *priv)
+{
+ /* Release the DMA TX/RX socket buffers */
+ dma_free_rx_skbufs(priv);
+ dma_free_tx_skbufs(priv);
+
+ /* Free the region of consistent memory previously allocated for
+ * the DMA */
+ dma_free_coherent(priv->device,
+ priv->dma_tx_size * sizeof(struct dma_desc),
+ priv->dma_tx, priv->dma_tx_phy);
+ dma_free_coherent(priv->device,
+ priv->dma_rx_size * sizeof(struct dma_desc),
+ priv->dma_rx, priv->dma_rx_phy);
+ kfree(priv->rx_skbuff_dma);
+ kfree(priv->rx_skbuff);
+ kfree(priv->tx_skbuff);
+
+ return;
+}
+
+/**
+ * stmmac_dma_start_tx
+ * @ioaddr: device I/O address
+ * Description: this function starts the DMA tx process.
+ */
+static void stmmac_dma_start_tx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + DMA_CONTROL);
+ value |= DMA_CONTROL_ST;
+ writel(value, ioaddr + DMA_CONTROL);
+ return;
+}
+
+static void stmmac_dma_stop_tx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + DMA_CONTROL);
+ value &= ~DMA_CONTROL_ST;
+ writel(value, ioaddr + DMA_CONTROL);
+ return;
+}
+
+/**
+ * stmmac_dma_start_rx
+ * @ioaddr: device I/O address
+ * Description: this function starts the DMA rx process.
+ */
+static void stmmac_dma_start_rx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + DMA_CONTROL);
+ value |= DMA_CONTROL_SR;
+ writel(value, ioaddr + DMA_CONTROL);
+
+ return;
+}
+
+static void stmmac_dma_stop_rx(unsigned long ioaddr)
+{
+ u32 value = readl(ioaddr + DMA_CONTROL);
+ value &= ~DMA_CONTROL_SR;
+ writel(value, ioaddr + DMA_CONTROL);
+
+ return;
+}
+
+/**
+ * stmmac_dma_operation_mode - HW DMA operation mode
+ * @priv : pointer to the private device structure.
+ * Description: it sets the DMA operation mode: tx/rx DMA thresholds
+ * or Store-And-Forward capability. It also verifies the COE for the
+ * transmission in case of Giga ETH.
+ */
+static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
+{
+ if (!priv->is_gmac) {
+ /* MAC 10/100 */
+ priv->mac_type->ops->dma_mode(priv->dev->base_addr, tc, 0);
+ priv->tx_coe = NO_HW_CSUM;
+ } else {
+ if ((priv->dev->mtu <= ETH_DATA_LEN) && (tx_coe)) {
+ priv->mac_type->ops->dma_mode(priv->dev->base_addr,
+ SF_DMA_MODE, SF_DMA_MODE);
+ tc = SF_DMA_MODE;
+ priv->tx_coe = HW_CSUM;
+ } else {
+ /* Checksum computation is performed in software. */
+ priv->mac_type->ops->dma_mode(priv->dev->base_addr, tc,
+ SF_DMA_MODE);
+ priv->tx_coe = NO_HW_CSUM;
+ }
+ }
+ tx_coe = priv->tx_coe;
+
+ return;
+}
+
+#ifdef STMMAC_DEBUG
+/**
+ * show_tx_process_state
+ * @status: tx descriptor status field
+ * Description: it shows the Transmit Process State for CSR5[22:20]
+ */
+static void show_tx_process_state(unsigned int status)
+{
+ unsigned int state;
+ state = (status & DMA_STATUS_TS_MASK) >> DMA_STATUS_TS_SHIFT;
+
+ switch (state) {
+ case 0:
+ pr_info("- TX (Stopped): Reset or Stop command\n");
+ break;
+ case 1:
+ pr_info("- TX (Running):Fetching the Tx desc\n");
+ break;
+ case 2:
+ pr_info("- TX (Running): Waiting for end of tx\n");
+ break;
+ case 3:
+ pr_info("- TX (Running): Reading the data "
+ "and queuing the data into the Tx buf\n");
+ break;
+ case 6:
+ pr_info("- TX (Suspended): Tx Buff Underflow "
+ "or an unavailable Transmit descriptor\n");
+ break;
+ case 7:
+ pr_info("- TX (Running): Closing Tx descriptor\n");
+ break;
+ default:
+ break;
+ }
+ return;
+}
+
+/**
+ * show_rx_process_state
+ * @status: rx descriptor status field
+ * Description: it shows the Receive Process State for CSR5[19:17]
+ */
+static void show_rx_process_state(unsigned int status)
+{
+ unsigned int state;
+ state = (status & DMA_STATUS_RS_MASK) >> DMA_STATUS_RS_SHIFT;
+
+ switch (state) {
+ case 0:
+ pr_info("- RX (Stopped): Reset or Stop command\n");
+ break;
+ case 1:
+ pr_info("- RX (Running): Fetching the Rx desc\n");
+ break;
+ case 2:
+ pr_info("- RX (Running):Checking for end of pkt\n");
+ break;
+ case 3:
+ pr_info("- RX (Running): Waiting for Rx pkt\n");
+ break;
+ case 4:
+ pr_info("- RX (Suspended): Unavailable Rx buf\n");
+ break;
+ case 5:
+ pr_info("- RX (Running): Closing Rx descriptor\n");
+ break;
+ case 6:
+ pr_info("- RX(Running): Flushing the current frame"
+ " from the Rx buf\n");
+ break;
+ case 7:
+ pr_info("- RX (Running): Queuing the Rx frame"
+ " from the Rx buf into memory\n");
+ break;
+ default:
+ break;
+ }
+ return;
+}
+#endif
+
+/**
+ * stmmac_tx:
+ * @priv: private driver structure
+ * Description: it reclaims resources after transmission completes.
+ */
+static void stmmac_tx(struct stmmac_priv *priv)
+{
+ unsigned int txsize = priv->dma_tx_size;
+ unsigned long ioaddr = priv->dev->base_addr;
+
+ while (priv->dirty_tx != priv->cur_tx) {
+ int last;
+ unsigned int entry = priv->dirty_tx % txsize;
+ struct sk_buff *skb = priv->tx_skbuff[entry];
+ struct dma_desc *p = priv->dma_tx + entry;
+
+ /* Check if the descriptor is owned by the DMA. */
+ if (priv->mac_type->ops->get_tx_owner(p))
+ break;
+
+ /* Verify tx error by looking at the last segment */
+ last = priv->mac_type->ops->get_tx_ls(p);
+ if (likely(last)) {
+ int tx_error =
+ priv->mac_type->ops->tx_status(&priv->dev->stats,
+ &priv->xstats,
+ p, ioaddr);
+ if (likely(tx_error == 0)) {
+ priv->dev->stats.tx_packets++;
+ priv->xstats.tx_pkt_n++;
+ } else
+ priv->dev->stats.tx_errors++;
+ }
+ TX_DBG("%s: curr %d, dirty %d\n", __func__,
+ priv->cur_tx, priv->dirty_tx);
+
+ if (likely(p->des2))
+ dma_unmap_single(priv->device, p->des2,
+ priv->mac_type->ops->get_tx_len(p),
+ DMA_TO_DEVICE);
+ if (unlikely(p->des3))
+ p->des3 = 0;
+
+ if (likely(skb != NULL)) {
+ /*
+ * If there's room in the queue (limit it to size)
+ * we add this skb back into the pool,
+ * if it's the right size.
+ */
+ if ((skb_queue_len(&priv->rx_recycle) <
+ priv->dma_rx_size) &&
+ skb_recycle_check(skb, priv->dma_buf_sz))
+ __skb_queue_head(&priv->rx_recycle, skb);
+ else
+ dev_kfree_skb(skb);
+
+ priv->tx_skbuff[entry] = NULL;
+ }
+
+ priv->mac_type->ops->release_tx_desc(p);
+
+ entry = (++priv->dirty_tx) % txsize;
+ }
+ if (unlikely(netif_queue_stopped(priv->dev) &&
+ stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) {
+ netif_tx_lock(priv->dev);
+ if (netif_queue_stopped(priv->dev) &&
+ stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv)) {
+ TX_DBG("%s: restart transmit\n", __func__);
+ netif_wake_queue(priv->dev);
+ }
+ netif_tx_unlock(priv->dev);
+ }
+ return;
+}
+
+static inline void stmmac_enable_irq(struct stmmac_priv *priv)
+{
+#ifndef CONFIG_STMMAC_TIMER
+ writel(DMA_INTR_DEFAULT_MASK, priv->dev->base_addr + DMA_INTR_ENA);
+#else
+ priv->tm->timer_start(tmrate);
+#endif
+}
+
+static inline void stmmac_disable_irq(struct stmmac_priv *priv)
+{
+#ifndef CONFIG_STMMAC_TIMER
+ writel(0, priv->dev->base_addr + DMA_INTR_ENA);
+#else
+ priv->tm->timer_stop();
+#endif
+}
+
+static int stmmac_has_work(struct stmmac_priv *priv)
+{
+ unsigned int has_work = 0;
+ int rxret, tx_work = 0;
+
+ rxret = priv->mac_type->ops->get_rx_owner(priv->dma_rx +
+ (priv->cur_rx % priv->dma_rx_size));
+
+ if (priv->dirty_tx != priv->cur_tx)
+ tx_work = 1;
+
+ if (likely(!rxret || tx_work))
+ has_work = 1;
+
+ return has_work;
+}
+
+static inline void _stmmac_schedule(struct stmmac_priv *priv)
+{
+ if (likely(stmmac_has_work(priv))) {
+ stmmac_disable_irq(priv);
+ napi_schedule(&priv->napi);
+ }
+}
+
+#ifdef CONFIG_STMMAC_TIMER
+void stmmac_schedule(struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ priv->xstats.sched_timer_n++;
+
+ _stmmac_schedule(priv);
+
+ return;
+}
+
+static void stmmac_no_timer_started(unsigned int x)
+{;
+};
+
+static void stmmac_no_timer_stopped(void)
+{;
+};
+#endif
+
+/**
+ * stmmac_tx_err:
+ * @priv: pointer to the private device structure
+ * Description: it cleans the descriptors and restarts the transmission
+ * in case of errors.
+ */
+static void stmmac_tx_err(struct stmmac_priv *priv)
+{
+ netif_stop_queue(priv->dev);
+
+ stmmac_dma_stop_tx(priv->dev->base_addr);
+ dma_free_tx_skbufs(priv);
+ priv->mac_type->ops->init_tx_desc(priv->dma_tx, priv->dma_tx_size);
+ priv->dirty_tx = 0;
+ priv->cur_tx = 0;
+ stmmac_dma_start_tx(priv->dev->base_addr);
+
+ priv->dev->stats.tx_errors++;
+ netif_wake_queue(priv->dev);
+
+ return;
+}
+
+/**
+ * stmmac_dma_interrupt - Interrupt handler for the driver
+ * @dev: net device structure
+ * Description: Interrupt handler for the driver (DMA).
+ */
+static void stmmac_dma_interrupt(struct net_device *dev)
+{
+ unsigned long ioaddr = dev->base_addr;
+ struct stmmac_priv *priv = netdev_priv(dev);
+ /* read the status register (CSR5) */
+ u32 intr_status = readl(ioaddr + DMA_STATUS);
+
+ DBG(intr, INFO, "%s: [CSR5: 0x%08x]\n", __func__, intr_status);
+
+#ifdef STMMAC_DEBUG
+ /* It displays the DMA transmit process state (CSR5 register) */
+ if (netif_msg_tx_done(priv))
+ show_tx_process_state(intr_status);
+ if (netif_msg_rx_status(priv))
+ show_rx_process_state(intr_status);
+#endif
+ /* ABNORMAL interrupts */
+ if (unlikely(intr_status & DMA_STATUS_AIS)) {
+ DBG(intr, INFO, "CSR5[15] DMA ABNORMAL IRQ: ");
+ if (unlikely(intr_status & DMA_STATUS_UNF)) {
+ DBG(intr, INFO, "transmit underflow\n");
+ if (unlikely(tc != SF_DMA_MODE)
+ && (tc <= 256)) {
+ /* Try to bump up the threshold */
+ tc += 64;
+ priv->mac_type->ops->dma_mode(ioaddr, tc,
+ SF_DMA_MODE);
+ priv->xstats.threshold = tc;
+ }
+ stmmac_tx_err(priv);
+ priv->xstats.tx_undeflow_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_TJT)) {
+ DBG(intr, INFO, "transmit jabber\n");
+ priv->xstats.tx_jabber_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_OVF)) {
+ DBG(intr, INFO, "recv overflow\n");
+ priv->xstats.rx_overflow_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_RU)) {
+ DBG(intr, INFO, "receive buffer unavailable\n");
+ priv->xstats.rx_buf_unav_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_RPS)) {
+ DBG(intr, INFO, "receive process stopped\n");
+ priv->xstats.rx_process_stopped_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_RWT)) {
+ DBG(intr, INFO, "receive watchdog\n");
+ priv->xstats.rx_watchdog_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_ETI)) {
+ DBG(intr, INFO, "transmit early interrupt\n");
+ priv->xstats.tx_early_irq++;
+ }
+ if (unlikely(intr_status & DMA_STATUS_TPS)) {
+ DBG(intr, INFO, "transmit process stopped\n");
+ priv->xstats.tx_process_stopped_irq++;
+ stmmac_tx_err(priv);
+ }
+ if (unlikely(intr_status & DMA_STATUS_FBI)) {
+ DBG(intr, INFO, "fatal bus error\n");
+ priv->xstats.fatal_bus_error_irq++;
+ stmmac_tx_err(priv);
+ }
+ }
+
+ /* TX/RX NORMAL interrupts */
+ if (intr_status & DMA_STATUS_NIS) {
+ priv->xstats.normal_irq_n++;
+ if (likely((intr_status & DMA_STATUS_RI) ||
+ (intr_status & (DMA_STATUS_TI))))
+ _stmmac_schedule(priv);
+ }
+
+ /* Optional hardware blocks, interrupts should be disabled */
+ if (unlikely(intr_status &
+ (DMA_STATUS_GPI | DMA_STATUS_GMI | DMA_STATUS_GLI)))
+ pr_info("%s: unexpected status %08x\n", __func__, intr_status);
+
+ /* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
+ writel((intr_status & 0x1ffff), ioaddr + DMA_STATUS);
+
+ DBG(intr, INFO, "\n\n");
+
+ return;
+}
+
+/**
+ * stmmac_open - open entry point of the driver
+ * @dev : pointer to the device structure.
+ * Description:
+ * This function is the open entry point of the driver.
+ * Return value:
+ * 0 on success and an appropriate (-)ve integer as defined in errno.h
+ * file on failure.
+ */
+static int stmmac_open(struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+ int ret;
+
+ /* Check that the MAC address is valid. If its not, refuse
+ * to bring the device up. The user must specify an
+ * address using the following linux command:
+ * ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx */
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ random_ether_addr(dev->dev_addr);
+ pr_warning("%s: generated random MAC address %pM\n", dev->name,
+ dev->dev_addr);
+ }
+
+ stmmac_verify_args();
+
+ ret = stmmac_init_phy(dev);
+ if (unlikely(ret)) {
+ pr_err("%s: Cannot attach to PHY (error: %d)\n", __func__, ret);
+ return ret;
+ }
+
+ /* Request the IRQ lines */
+ ret = request_irq(dev->irq, &stmmac_interrupt,
+ IRQF_SHARED, dev->name, dev);
+ if (unlikely(ret < 0)) {
+ pr_err("%s: ERROR: allocating the IRQ %d (error: %d)\n",
+ __func__, dev->irq, ret);
+ return ret;
+ }
+
+#ifdef CONFIG_STMMAC_TIMER
+ priv->tm = kmalloc(sizeof(struct stmmac_timer *), GFP_KERNEL);
+ if (unlikely(priv->tm == NULL)) {
+ pr_err("%s: ERROR: timer memory alloc failed \n", __func__);
+ return -ENOMEM;
+ }
+ priv->tm->freq = tmrate;
+
+ /* Test if the HW timer can be actually used.
+ * In case of failure continue with no timer. */
+ if (unlikely((stmmac_open_ext_timer(dev, priv->tm)) < 0)) {
+ pr_warning("stmmaceth: cannot attach the HW timer\n");
+ tmrate = 0;
+ priv->tm->freq = 0;
+ priv->tm->timer_start = stmmac_no_timer_started;
+ priv->tm->timer_stop = stmmac_no_timer_stopped;
+ }
+#endif
+
+ /* Create and initialize the TX/RX descriptors chains. */
+ priv->dma_tx_size = STMMAC_ALIGN(dma_txsize);
+ priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize);
+ priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
+ init_dma_desc_rings(dev);
+
+ /* DMA initialization and SW reset */
+ if (unlikely(priv->mac_type->ops->dma_init(ioaddr,
+ priv->pbl, priv->dma_tx_phy, priv->dma_rx_phy) < 0)) {
+
+ pr_err("%s: DMA initialization failed\n", __func__);
+ return -1;
+ }
+
+ /* Copy the MAC addr into the HW */
+ priv->mac_type->ops->set_umac_addr(ioaddr, dev->dev_addr, 0);
+ /* Initialize the MAC Core */
+ priv->mac_type->ops->core_init(ioaddr);
+
+ priv->shutdown = 0;
+
+ /* Initialise the MMC (if present) to disable all interrupts. */
+ writel(0xffffffff, ioaddr + MMC_HIGH_INTR_MASK);
+ writel(0xffffffff, ioaddr + MMC_LOW_INTR_MASK);
+
+ /* Enable the MAC Rx/Tx */
+ stmmac_mac_enable_rx(ioaddr);
+ stmmac_mac_enable_tx(ioaddr);
+
+ /* Set the HW DMA mode and the COE */
+ stmmac_dma_operation_mode(priv);
+
+ /* Extra statistics */
+ memset(&priv->xstats, 0, sizeof(struct stmmac_extra_stats));
+ priv->xstats.threshold = tc;
+
+ /* Start the ball rolling... */
+ DBG(probe, DEBUG, "%s: DMA RX/TX processes started...\n", dev->name);
+ stmmac_dma_start_tx(ioaddr);
+ stmmac_dma_start_rx(ioaddr);
+
+#ifdef CONFIG_STMMAC_TIMER
+ priv->tm->timer_start(tmrate);
+#endif
+ /* Dump DMA/MAC registers */
+ if (netif_msg_hw(priv)) {
+ priv->mac_type->ops->dump_mac_regs(ioaddr);
+ priv->mac_type->ops->dump_dma_regs(ioaddr);
+ }
+
+ if (priv->phydev)
+ phy_start(priv->phydev);
+
+ napi_enable(&priv->napi);
+ skb_queue_head_init(&priv->rx_recycle);
+ netif_start_queue(dev);
+ return 0;
+}
+
+/**
+ * stmmac_release - close entry point of the driver
+ * @dev : device pointer.
+ * Description:
+ * This is the stop entry point of the driver.
+ */
+static int stmmac_release(struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ /* Stop and disconnect the PHY */
+ if (priv->phydev) {
+ phy_stop(priv->phydev);
+ phy_disconnect(priv->phydev);
+ priv->phydev = NULL;
+ }
+
+ netif_stop_queue(dev);
+
+#ifdef CONFIG_STMMAC_TIMER
+ /* Stop and release the timer */
+ stmmac_close_ext_timer();
+ if (priv->tm != NULL)
+ kfree(priv->tm);
+#endif
+ napi_disable(&priv->napi);
+ skb_queue_purge(&priv->rx_recycle);
+
+ /* Free the IRQ lines */
+ free_irq(dev->irq, dev);
+
+ /* Stop TX/RX DMA and clear the descriptors */
+ stmmac_dma_stop_tx(dev->base_addr);
+ stmmac_dma_stop_rx(dev->base_addr);
+
+ /* Release and free the Rx/Tx resources */
+ free_dma_desc_resources(priv);
+
+ /* Disable the MAC core */
+ stmmac_mac_disable_tx(dev->base_addr);
+ stmmac_mac_disable_rx(dev->base_addr);
+
+ netif_carrier_off(dev);
+
+ return 0;
+}
+
+/*
+ * To perform emulated hardware segmentation on skb.
+ */
+static int stmmac_sw_tso(struct stmmac_priv *priv, struct sk_buff *skb)
+{
+ struct sk_buff *segs, *curr_skb;
+ int gso_segs = skb_shinfo(skb)->gso_segs;
+
+ /* Estimate the number of fragments in the worst case */
+ if (unlikely(stmmac_tx_avail(priv) < gso_segs)) {
+ netif_stop_queue(priv->dev);
+ TX_DBG(KERN_ERR "%s: TSO BUG! Tx Ring full when queue awake\n",
+ __func__);
+ if (stmmac_tx_avail(priv) < gso_segs)
+ return NETDEV_TX_BUSY;
+
+ netif_wake_queue(priv->dev);
+ }
+ TX_DBG("\tstmmac_sw_tso: segmenting: skb %p (len %d)\n",
+ skb, skb->len);
+
+ segs = skb_gso_segment(skb, priv->dev->features & ~NETIF_F_TSO);
+ if (unlikely(IS_ERR(segs)))
+ goto sw_tso_end;
+
+ do {
+ curr_skb = segs;
+ segs = segs->next;
+ TX_DBG("\t\tcurrent skb->len: %d, *curr %p,"
+ "*next %p\n", curr_skb->len, curr_skb, segs);
+ curr_skb->next = NULL;
+ stmmac_xmit(curr_skb, priv->dev);
+ } while (segs);
+
+sw_tso_end:
+ dev_kfree_skb(skb);
+
+ return NETDEV_TX_OK;
+}
+
+static unsigned int stmmac_handle_jumbo_frames(struct sk_buff *skb,
+ struct net_device *dev,
+ int csum_insertion)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ unsigned int nopaged_len = skb_headlen(skb);
+ unsigned int txsize = priv->dma_tx_size;
+ unsigned int entry = priv->cur_tx % txsize;
+ struct dma_desc *desc = priv->dma_tx + entry;
+
+ if (nopaged_len > BUF_SIZE_8KiB) {
+
+ int buf2_size = nopaged_len - BUF_SIZE_8KiB;
+
+ desc->des2 = dma_map_single(priv->device, skb->data,
+ BUF_SIZE_8KiB, DMA_TO_DEVICE);
+ desc->des3 = desc->des2 + BUF_SIZE_4KiB;
+ priv->mac_type->ops->prepare_tx_desc(desc, 1, BUF_SIZE_8KiB,
+ csum_insertion);
+
+ entry = (++priv->cur_tx) % txsize;
+ desc = priv->dma_tx + entry;
+
+ desc->des2 = dma_map_single(priv->device,
+ skb->data + BUF_SIZE_8KiB,
+ buf2_size, DMA_TO_DEVICE);
+ desc->des3 = desc->des2 + BUF_SIZE_4KiB;
+ priv->mac_type->ops->prepare_tx_desc(desc, 0,
+ buf2_size, csum_insertion);
+ priv->mac_type->ops->set_tx_owner(desc);
+ priv->tx_skbuff[entry] = NULL;
+ } else {
+ desc->des2 = dma_map_single(priv->device, skb->data,
+ nopaged_len, DMA_TO_DEVICE);
+ desc->des3 = desc->des2 + BUF_SIZE_4KiB;
+ priv->mac_type->ops->prepare_tx_desc(desc, 1, nopaged_len,
+ csum_insertion);
+ }
+ return entry;
+}
+
+/**
+ * stmmac_xmit:
+ * @skb : the socket buffer
+ * @dev : device pointer
+ * Description : Tx entry point of the driver.
+ */
+static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ unsigned int txsize = priv->dma_tx_size;
+ unsigned int entry;
+ int i, csum_insertion = 0;
+ int nfrags = skb_shinfo(skb)->nr_frags;
+ struct dma_desc *desc, *first;
+
+ if (unlikely(stmmac_tx_avail(priv) < nfrags + 1)) {
+ if (!netif_queue_stopped(dev)) {
+ netif_stop_queue(dev);
+ /* This is a hard error, log it. */
+ pr_err("%s: BUG! Tx Ring full when queue awake\n",
+ __func__);
+ }
+ return NETDEV_TX_BUSY;
+ }
+
+ entry = priv->cur_tx % txsize;
+
+#ifdef STMMAC_XMIT_DEBUG
+ if ((skb->len > ETH_FRAME_LEN) || nfrags)
+ pr_info("stmmac xmit:\n"
+ "\tskb addr %p - len: %d - nopaged_len: %d\n"
+ "\tn_frags: %d - ip_summed: %d - %s gso\n",
+ skb, skb->len, skb_headlen(skb), nfrags, skb->ip_summed,
+ !skb_is_gso(skb) ? "isn't" : "is");
+#endif
+
+ if (unlikely(skb_is_gso(skb)))
+ return stmmac_sw_tso(priv, skb);
+
+ if (likely((skb->ip_summed == CHECKSUM_PARTIAL))) {
+ if (likely(priv->tx_coe == NO_HW_CSUM))
+ skb_checksum_help(skb);
+ else
+ csum_insertion = 1;
+ }
+
+ desc = priv->dma_tx + entry;
+ first = desc;
+
+#ifdef STMMAC_XMIT_DEBUG
+ if ((nfrags > 0) || (skb->len > ETH_FRAME_LEN))
+ pr_debug("stmmac xmit: skb len: %d, nopaged_len: %d,\n"
+ "\t\tn_frags: %d, ip_summed: %d\n",
+ skb->len, skb_headlen(skb), nfrags, skb->ip_summed);
+#endif
+ priv->tx_skbuff[entry] = skb;
+ if (unlikely(skb->len >= BUF_SIZE_4KiB)) {
+ entry = stmmac_handle_jumbo_frames(skb, dev, csum_insertion);
+ desc = priv->dma_tx + entry;
+ } else {
+ unsigned int nopaged_len = skb_headlen(skb);
+ desc->des2 = dma_map_single(priv->device, skb->data,
+ nopaged_len, DMA_TO_DEVICE);
+ priv->mac_type->ops->prepare_tx_desc(desc, 1, nopaged_len,
+ csum_insertion);
+ }
+
+ for (i = 0; i < nfrags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ int len = frag->size;
+
+ entry = (++priv->cur_tx) % txsize;
+ desc = priv->dma_tx + entry;
+
+ TX_DBG("\t[entry %d] segment len: %d\n", entry, len);
+ desc->des2 = dma_map_page(priv->device, frag->page,
+ frag->page_offset,
+ len, DMA_TO_DEVICE);
+ priv->tx_skbuff[entry] = NULL;
+ priv->mac_type->ops->prepare_tx_desc(desc, 0, len,
+ csum_insertion);
+ priv->mac_type->ops->set_tx_owner(desc);
+ }
+
+ /* Interrupt on completition only for the latest segment */
+ priv->mac_type->ops->close_tx_desc(desc);
+#ifdef CONFIG_STMMAC_TIMER
+ /* Clean IC while using timers */
+ priv->mac_type->ops->clear_tx_ic(desc);
+#endif
+ /* To avoid raise condition */
+ priv->mac_type->ops->set_tx_owner(first);
+
+ priv->cur_tx++;
+
+#ifdef STMMAC_XMIT_DEBUG
+ if (netif_msg_pktdata(priv)) {
+ pr_info("stmmac xmit: current=%d, dirty=%d, entry=%d, "
+ "first=%p, nfrags=%d\n",
+ (priv->cur_tx % txsize), (priv->dirty_tx % txsize),
+ entry, first, nfrags);
+ display_ring(priv->dma_tx, txsize);
+ pr_info(">>> frame to be transmitted: ");
+ print_pkt(skb->data, skb->len);
+ }
+#endif
+ if (unlikely(stmmac_tx_avail(priv) <= (MAX_SKB_FRAGS + 1))) {
+ TX_DBG("%s: stop transmitted packets\n", __func__);
+ netif_stop_queue(dev);
+ }
+
+ dev->stats.tx_bytes += skb->len;
+
+ /* CSR1 enables the transmit DMA to check for new descriptor */
+ writel(1, dev->base_addr + DMA_XMT_POLL_DEMAND);
+
+ return NETDEV_TX_OK;
+}
+
+static inline void stmmac_rx_refill(struct stmmac_priv *priv)
+{
+ unsigned int rxsize = priv->dma_rx_size;
+ int bfsize = priv->dma_buf_sz;
+ struct dma_desc *p = priv->dma_rx;
+
+ for (; priv->cur_rx - priv->dirty_rx > 0; priv->dirty_rx++) {
+ unsigned int entry = priv->dirty_rx % rxsize;
+ if (likely(priv->rx_skbuff[entry] == NULL)) {
+ struct sk_buff *skb;
+
+ skb = __skb_dequeue(&priv->rx_recycle);
+ if (skb == NULL)
+ skb = netdev_alloc_skb_ip_align(priv->dev,
+ bfsize);
+
+ if (unlikely(skb == NULL))
+ break;
+
+ priv->rx_skbuff[entry] = skb;
+ priv->rx_skbuff_dma[entry] =
+ dma_map_single(priv->device, skb->data, bfsize,
+ DMA_FROM_DEVICE);
+
+ (p + entry)->des2 = priv->rx_skbuff_dma[entry];
+ if (unlikely(priv->is_gmac)) {
+ if (bfsize >= BUF_SIZE_8KiB)
+ (p + entry)->des3 =
+ (p + entry)->des2 + BUF_SIZE_8KiB;
+ }
+ RX_DBG(KERN_INFO "\trefill entry #%d\n", entry);
+ }
+ priv->mac_type->ops->set_rx_owner(p + entry);
+ }
+ return;
+}
+
+static int stmmac_rx(struct stmmac_priv *priv, int limit)
+{
+ unsigned int rxsize = priv->dma_rx_size;
+ unsigned int entry = priv->cur_rx % rxsize;
+ unsigned int next_entry;
+ unsigned int count = 0;
+ struct dma_desc *p = priv->dma_rx + entry;
+ struct dma_desc *p_next;
+
+#ifdef STMMAC_RX_DEBUG
+ if (netif_msg_hw(priv)) {
+ pr_debug(">>> stmmac_rx: descriptor ring:\n");
+ display_ring(priv->dma_rx, rxsize);
+ }
+#endif
+ count = 0;
+ while (!priv->mac_type->ops->get_rx_owner(p)) {
+ int status;
+
+ if (count >= limit)
+ break;
+
+ count++;
+
+ next_entry = (++priv->cur_rx) % rxsize;
+ p_next = priv->dma_rx + next_entry;
+ prefetch(p_next);
+
+ /* read the status of the incoming frame */
+ status = (priv->mac_type->ops->rx_status(&priv->dev->stats,
+ &priv->xstats, p));
+ if (unlikely(status == discard_frame))
+ priv->dev->stats.rx_errors++;
+ else {
+ struct sk_buff *skb;
+ /* Length should omit the CRC */
+ int frame_len =
+ priv->mac_type->ops->get_rx_frame_len(p) - 4;
+
+#ifdef STMMAC_RX_DEBUG
+ if (frame_len > ETH_FRAME_LEN)
+ pr_debug("\tRX frame size %d, COE status: %d\n",
+ frame_len, status);
+
+ if (netif_msg_hw(priv))
+ pr_debug("\tdesc: %p [entry %d] buff=0x%x\n",
+ p, entry, p->des2);
+#endif
+ skb = priv->rx_skbuff[entry];
+ if (unlikely(!skb)) {
+ pr_err("%s: Inconsistent Rx descriptor chain\n",
+ priv->dev->name);
+ priv->dev->stats.rx_dropped++;
+ break;
+ }
+ prefetch(skb->data - NET_IP_ALIGN);
+ priv->rx_skbuff[entry] = NULL;
+
+ skb_put(skb, frame_len);
+ dma_unmap_single(priv->device,
+ priv->rx_skbuff_dma[entry],
+ priv->dma_buf_sz, DMA_FROM_DEVICE);
+#ifdef STMMAC_RX_DEBUG
+ if (netif_msg_pktdata(priv)) {
+ pr_info(" frame received (%dbytes)", frame_len);
+ print_pkt(skb->data, frame_len);
+ }
+#endif
+ skb->protocol = eth_type_trans(skb, priv->dev);
+
+ if (unlikely(status == csum_none)) {
+ /* always for the old mac 10/100 */
+ skb->ip_summed = CHECKSUM_NONE;
+ netif_receive_skb(skb);
+ } else {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ napi_gro_receive(&priv->napi, skb);
+ }
+
+ priv->dev->stats.rx_packets++;
+ priv->dev->stats.rx_bytes += frame_len;
+ priv->dev->last_rx = jiffies;
+ }
+ entry = next_entry;
+ p = p_next; /* use prefetched values */
+ }
+
+ stmmac_rx_refill(priv);
+
+ priv->xstats.rx_pkt_n += count;
+
+ return count;
+}
+
+/**
+ * stmmac_poll - stmmac poll method (NAPI)
+ * @napi : pointer to the napi structure.
+ * @budget : maximum number of packets that the current CPU can receive from
+ * all interfaces.
+ * Description :
+ * This function implements the the reception process.
+ * Also it runs the TX completion thread
+ */
+static int stmmac_poll(struct napi_struct *napi, int budget)
+{
+ struct stmmac_priv *priv = container_of(napi, struct stmmac_priv, napi);
+ int work_done = 0;
+
+ priv->xstats.poll_n++;
+ stmmac_tx(priv);
+ work_done = stmmac_rx(priv, budget);
+
+ if (work_done < budget) {
+ napi_complete(napi);
+ stmmac_enable_irq(priv);
+ }
+ return work_done;
+}
+
+/**
+ * stmmac_tx_timeout
+ * @dev : Pointer to net device structure
+ * Description: this function is called when a packet transmission fails to
+ * complete within a reasonable tmrate. The driver will mark the error in the
+ * netdev structure and arrange for the device to be reset to a sane state
+ * in order to transmit a new packet.
+ */
+static void stmmac_tx_timeout(struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ /* Clear Tx resources and restart transmitting again */
+ stmmac_tx_err(priv);
+ return;
+}
+
+/* Configuration changes (passed on by ifconfig) */
+static int stmmac_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) {
+ pr_warning("%s: can't change I/O address\n", dev->name);
+ return -EOPNOTSUPP;
+ }
+
+ /* Don't allow changing the IRQ */
+ if (map->irq != dev->irq) {
+ pr_warning("%s: can't change IRQ number %d\n",
+ dev->name, dev->irq);
+ return -EOPNOTSUPP;
+ }
+
+ /* ignore other fields */
+ return 0;
+}
+
+/**
+ * stmmac_multicast_list - entry point for multicast addressing
+ * @dev : pointer to the device structure
+ * Description:
+ * This function is a driver entry point which gets called by the kernel
+ * whenever multicast addresses must be enabled/disabled.
+ * Return value:
+ * void.
+ */
+static void stmmac_multicast_list(struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ spin_lock(&priv->lock);
+ priv->mac_type->ops->set_filter(dev);
+ spin_unlock(&priv->lock);
+ return;
+}
+
+/**
+ * stmmac_change_mtu - entry point to change MTU size for the device.
+ * @dev : device pointer.
+ * @new_mtu : the new MTU size for the device.
+ * Description: the Maximum Transfer Unit (MTU) is used by the network layer
+ * to drive packet transmission. Ethernet has an MTU of 1500 octets
+ * (ETH_DATA_LEN). This value can be changed with ifconfig.
+ * Return value:
+ * 0 on success and an appropriate (-)ve integer as defined in errno.h
+ * file on failure.
+ */
+static int stmmac_change_mtu(struct net_device *dev, int new_mtu)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ int max_mtu;
+
+ if (netif_running(dev)) {
+ pr_err("%s: must be stopped to change its MTU\n", dev->name);
+ return -EBUSY;
+ }
+
+ if (priv->is_gmac)
+ max_mtu = JUMBO_LEN;
+ else
+ max_mtu = ETH_DATA_LEN;
+
+ if ((new_mtu < 46) || (new_mtu > max_mtu)) {
+ pr_err("%s: invalid MTU, max MTU is: %d\n", dev->name, max_mtu);
+ return -EINVAL;
+ }
+
+ dev->mtu = new_mtu;
+
+ return 0;
+}
+
+static irqreturn_t stmmac_interrupt(int irq, void *dev_id)
+{
+ struct net_device *dev = (struct net_device *)dev_id;
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ if (unlikely(!dev)) {
+ pr_err("%s: invalid dev pointer\n", __func__);
+ return IRQ_NONE;
+ }
+
+ if (priv->is_gmac) {
+ unsigned long ioaddr = dev->base_addr;
+ /* To handle GMAC own interrupts */
+ priv->mac_type->ops->host_irq_status(ioaddr);
+ }
+ stmmac_dma_interrupt(dev);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+/* Polling receive - used by NETCONSOLE and other diagnostic tools
+ * to allow network I/O with interrupts disabled. */
+static void stmmac_poll_controller(struct net_device *dev)
+{
+ disable_irq(dev->irq);
+ stmmac_interrupt(dev->irq, dev);
+ enable_irq(dev->irq);
+}
+#endif
+
+/**
+ * stmmac_ioctl - Entry point for the Ioctl
+ * @dev: Device pointer.
+ * @rq: An IOCTL specefic structure, that can contain a pointer to
+ * a proprietary structure used to pass information to the driver.
+ * @cmd: IOCTL command
+ * Description:
+ * Currently there are no special functionality supported in IOCTL, just the
+ * phy_mii_ioctl(...) can be invoked.
+ */
+static int stmmac_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ int ret = -EOPNOTSUPP;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+
+ switch (cmd) {
+ case SIOCGMIIPHY:
+ case SIOCGMIIREG:
+ case SIOCSMIIREG:
+ if (!priv->phydev)
+ return -EINVAL;
+
+ spin_lock(&priv->lock);
+ ret = phy_mii_ioctl(priv->phydev, if_mii(rq), cmd);
+ spin_unlock(&priv->lock);
+ default:
+ break;
+ }
+ return ret;
+}
+
+#ifdef STMMAC_VLAN_TAG_USED
+static void stmmac_vlan_rx_register(struct net_device *dev,
+ struct vlan_group *grp)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ DBG(probe, INFO, "%s: Setting vlgrp to %p\n", dev->name, grp);
+
+ spin_lock(&priv->lock);
+ priv->vlgrp = grp;
+ spin_unlock(&priv->lock);
+
+ return;
+}
+#endif
+
+static const struct net_device_ops stmmac_netdev_ops = {
+ .ndo_open = stmmac_open,
+ .ndo_start_xmit = stmmac_xmit,
+ .ndo_stop = stmmac_release,
+ .ndo_change_mtu = stmmac_change_mtu,
+ .ndo_set_multicast_list = stmmac_multicast_list,
+ .ndo_tx_timeout = stmmac_tx_timeout,
+ .ndo_do_ioctl = stmmac_ioctl,
+ .ndo_set_config = stmmac_config,
+#ifdef STMMAC_VLAN_TAG_USED
+ .ndo_vlan_rx_register = stmmac_vlan_rx_register,
+#endif
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = stmmac_poll_controller,
+#endif
+ .ndo_set_mac_address = eth_mac_addr,
+};
+
+/**
+ * stmmac_probe - Initialization of the adapter .
+ * @dev : device pointer
+ * Description: The function initializes the network device structure for
+ * the STMMAC driver. It also calls the low level routines
+ * in order to init the HW (i.e. the DMA engine)
+ */
+static int stmmac_probe(struct net_device *dev)
+{
+ int ret = 0;
+ struct stmmac_priv *priv = netdev_priv(dev);
+
+ ether_setup(dev);
+
+ dev->netdev_ops = &stmmac_netdev_ops;
+ stmmac_set_ethtool_ops(dev);
+
+ dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA);
+ dev->watchdog_timeo = msecs_to_jiffies(watchdog);
+#ifdef STMMAC_VLAN_TAG_USED
+ /* Both mac100 and gmac support receive VLAN tag detection */
+ dev->features |= NETIF_F_HW_VLAN_RX;
+#endif
+ priv->msg_enable = netif_msg_init(debug, default_msg_level);
+
+ if (priv->is_gmac)
+ priv->rx_csum = 1;
+
+ if (flow_ctrl)
+ priv->flow_ctrl = FLOW_AUTO; /* RX/TX pause on */
+
+ priv->pause = pause;
+ netif_napi_add(dev, &priv->napi, stmmac_poll, 64);
+
+ /* Get the MAC address */
+ priv->mac_type->ops->get_umac_addr(dev->base_addr, dev->dev_addr, 0);
+
+ if (!is_valid_ether_addr(dev->dev_addr))
+ pr_warning("\tno valid MAC address;"
+ "please, use ifconfig or nwhwconfig!\n");
+
+ ret = register_netdev(dev);
+ if (ret) {
+ pr_err("%s: ERROR %i registering the device\n",
+ __func__, ret);
+ return -ENODEV;
+ }
+
+ DBG(probe, DEBUG, "%s: Scatter/Gather: %s - HW checksums: %s\n",
+ dev->name, (dev->features & NETIF_F_SG) ? "on" : "off",
+ (dev->features & NETIF_F_HW_CSUM) ? "on" : "off");
+
+ spin_lock_init(&priv->lock);
+
+ return ret;
+}
+
+/**
+ * stmmac_mac_device_setup
+ * @dev : device pointer
+ * Description: select and initialise the mac device (mac100 or Gmac).
+ */
+static int stmmac_mac_device_setup(struct net_device *dev)
+{
+ struct stmmac_priv *priv = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+
+ struct mac_device_info *device;
+
+ if (priv->is_gmac)
+ device = gmac_setup(ioaddr);
+ else
+ device = mac100_setup(ioaddr);
+
+ if (!device)
+ return -ENOMEM;
+
+ priv->mac_type = device;
+
+ priv->wolenabled = priv->mac_type->hw.pmt; /* PMT supported */
+ if (priv->wolenabled == PMT_SUPPORTED)
+ priv->wolopts = WAKE_MAGIC; /* Magic Frame */
+
+ return 0;
+}
+
+static int stmmacphy_dvr_probe(struct platform_device *pdev)
+{
+ struct plat_stmmacphy_data *plat_dat;
+ plat_dat = (struct plat_stmmacphy_data *)((pdev->dev).platform_data);
+
+ pr_debug("stmmacphy_dvr_probe: added phy for bus %d\n",
+ plat_dat->bus_id);
+
+ return 0;
+}
+
+static int stmmacphy_dvr_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver stmmacphy_driver = {
+ .driver = {
+ .name = PHY_RESOURCE_NAME,
+ },
+ .probe = stmmacphy_dvr_probe,
+ .remove = stmmacphy_dvr_remove,
+};
+
+/**
+ * stmmac_associate_phy
+ * @dev: pointer to device structure
+ * @data: points to the private structure.
+ * Description: Scans through all the PHYs we have registered and checks if
+ * any are associated with our MAC. If so, then just fill in
+ * the blanks in our local context structure
+ */
+static int stmmac_associate_phy(struct device *dev, void *data)
+{
+ struct stmmac_priv *priv = (struct stmmac_priv *)data;
+ struct plat_stmmacphy_data *plat_dat;
+
+ plat_dat = (struct plat_stmmacphy_data *)(dev->platform_data);
+
+ DBG(probe, DEBUG, "%s: checking phy for bus %d\n", __func__,
+ plat_dat->bus_id);
+
+ /* Check that this phy is for the MAC being initialised */
+ if (priv->bus_id != plat_dat->bus_id)
+ return 0;
+
+ /* OK, this PHY is connected to the MAC.
+ Go ahead and get the parameters */
+ DBG(probe, DEBUG, "%s: OK. Found PHY config\n", __func__);
+ priv->phy_irq =
+ platform_get_irq_byname(to_platform_device(dev), "phyirq");
+ DBG(probe, DEBUG, "%s: PHY irq on bus %d is %d\n", __func__,
+ plat_dat->bus_id, priv->phy_irq);
+
+ /* Override with kernel parameters if supplied XXX CRS XXX
+ * this needs to have multiple instances */
+ if ((phyaddr >= 0) && (phyaddr <= 31))
+ plat_dat->phy_addr = phyaddr;
+
+ priv->phy_addr = plat_dat->phy_addr;
+ priv->phy_mask = plat_dat->phy_mask;
+ priv->phy_interface = plat_dat->interface;
+ priv->phy_reset = plat_dat->phy_reset;
+
+ DBG(probe, DEBUG, "%s: exiting\n", __func__);
+ return 1; /* forces exit of driver_for_each_device() */
+}
+
+/**
+ * stmmac_dvr_probe
+ * @pdev: platform device pointer
+ * Description: the driver is initialized through platform_device.
+ */
+static int stmmac_dvr_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ struct resource *res;
+ unsigned int *addr = NULL;
+ struct net_device *ndev = NULL;
+ struct stmmac_priv *priv;
+ struct plat_stmmacenet_data *plat_dat;
+
+ pr_info("STMMAC driver:\n\tplatform registration... ");
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ ret = -ENODEV;
+ goto out;
+ }
+ pr_info("done!\n");
+
+ if (!request_mem_region(res->start, (res->end - res->start),
+ pdev->name)) {
+ pr_err("%s: ERROR: memory allocation failed"
+ "cannot get the I/O addr 0x%x\n",
+ __func__, (unsigned int)res->start);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ addr = ioremap(res->start, (res->end - res->start));
+ if (!addr) {
+ pr_err("%s: ERROR: memory mapping failed \n", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ndev = alloc_etherdev(sizeof(struct stmmac_priv));
+ if (!ndev) {
+ pr_err("%s: ERROR: allocating the device\n", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ /* Get the MAC information */
+ ndev->irq = platform_get_irq_byname(pdev, "macirq");
+ if (ndev->irq == -ENXIO) {
+ pr_err("%s: ERROR: MAC IRQ configuration "
+ "information not found\n", __func__);
+ ret = -ENODEV;
+ goto out;
+ }
+
+ priv = netdev_priv(ndev);
+ priv->device = &(pdev->dev);
+ priv->dev = ndev;
+ plat_dat = (struct plat_stmmacenet_data *)((pdev->dev).platform_data);
+ priv->bus_id = plat_dat->bus_id;
+ priv->pbl = plat_dat->pbl; /* TLI */
+ priv->is_gmac = plat_dat->has_gmac; /* GMAC is on board */
+
+ platform_set_drvdata(pdev, ndev);
+
+ /* Set the I/O base addr */
+ ndev->base_addr = (unsigned long)addr;
+
+ /* MAC HW revice detection */
+ ret = stmmac_mac_device_setup(ndev);
+ if (ret < 0)
+ goto out;
+
+ /* Network Device Registration */
+ ret = stmmac_probe(ndev);
+ if (ret < 0)
+ goto out;
+
+ /* associate a PHY - it is provided by another platform bus */
+ if (!driver_for_each_device
+ (&(stmmacphy_driver.driver), NULL, (void *)priv,
+ stmmac_associate_phy)) {
+ pr_err("No PHY device is associated with this MAC!\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ priv->fix_mac_speed = plat_dat->fix_mac_speed;
+ priv->bsp_priv = plat_dat->bsp_priv;
+
+ pr_info("\t%s - (dev. name: %s - id: %d, IRQ #%d\n"
+ "\tIO base addr: 0x%08x)\n", ndev->name, pdev->name,
+ pdev->id, ndev->irq, (unsigned int)addr);
+
+ /* MDIO bus Registration */
+ pr_debug("\tMDIO bus (id: %d)...", priv->bus_id);
+ ret = stmmac_mdio_register(ndev);
+ if (ret < 0)
+ goto out;
+ pr_debug("registered!\n");
+
+out:
+ if (ret < 0) {
+ platform_set_drvdata(pdev, NULL);
+ release_mem_region(res->start, (res->end - res->start));
+ if (addr != NULL)
+ iounmap(addr);
+ }
+
+ return ret;
+}
+
+/**
+ * stmmac_dvr_remove
+ * @pdev: platform device pointer
+ * Description: this function resets the TX/RX processes, disables the MAC RX/TX
+ * changes the link status, releases the DMA descriptor rings,
+ * unregisters the MDIO bus and unmaps the allocated memory.
+ */
+static int stmmac_dvr_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ pr_info("%s:\n\tremoving driver", __func__);
+
+ stmmac_dma_stop_rx(ndev->base_addr);
+ stmmac_dma_stop_tx(ndev->base_addr);
+
+ stmmac_mac_disable_rx(ndev->base_addr);
+ stmmac_mac_disable_tx(ndev->base_addr);
+
+ netif_carrier_off(ndev);
+
+ stmmac_mdio_unregister(ndev);
+
+ platform_set_drvdata(pdev, NULL);
+ unregister_netdev(ndev);
+
+ iounmap((void *)ndev->base_addr);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, (res->end - res->start));
+
+ free_netdev(ndev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int stmmac_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct stmmac_priv *priv = netdev_priv(dev);
+ int dis_ic = 0;
+
+ if (!dev || !netif_running(dev))
+ return 0;
+
+ spin_lock(&priv->lock);
+
+ if (state.event == PM_EVENT_SUSPEND) {
+ netif_device_detach(dev);
+ netif_stop_queue(dev);
+ if (priv->phydev)
+ phy_stop(priv->phydev);
+
+#ifdef CONFIG_STMMAC_TIMER
+ priv->tm->timer_stop();
+ dis_ic = 1;
+#endif
+ napi_disable(&priv->napi);
+
+ /* Stop TX/RX DMA */
+ stmmac_dma_stop_tx(dev->base_addr);
+ stmmac_dma_stop_rx(dev->base_addr);
+ /* Clear the Rx/Tx descriptors */
+ priv->mac_type->ops->init_rx_desc(priv->dma_rx,
+ priv->dma_rx_size, dis_ic);
+ priv->mac_type->ops->init_tx_desc(priv->dma_tx,
+ priv->dma_tx_size);
+
+ stmmac_mac_disable_tx(dev->base_addr);
+
+ if (device_may_wakeup(&(pdev->dev))) {
+ /* Enable Power down mode by programming the PMT regs */
+ if (priv->wolenabled == PMT_SUPPORTED)
+ priv->mac_type->ops->pmt(dev->base_addr,
+ priv->wolopts);
+ } else {
+ stmmac_mac_disable_rx(dev->base_addr);
+ }
+ } else {
+ priv->shutdown = 1;
+ /* Although this can appear slightly redundant it actually
+ * makes fast the standby operation and guarantees the driver
+ * working if hibernation is on media. */
+ stmmac_release(dev);
+ }
+
+ spin_unlock(&priv->lock);
+ return 0;
+}
+
+static int stmmac_resume(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct stmmac_priv *priv = netdev_priv(dev);
+ unsigned long ioaddr = dev->base_addr;
+
+ if (!netif_running(dev))
+ return 0;
+
+ spin_lock(&priv->lock);
+
+ if (priv->shutdown) {
+ /* Re-open the interface and re-init the MAC/DMA
+ and the rings. */
+ stmmac_open(dev);
+ goto out_resume;
+ }
+
+ /* Power Down bit, into the PM register, is cleared
+ * automatically as soon as a magic packet or a Wake-up frame
+ * is received. Anyway, it's better to manually clear
+ * this bit because it can generate problems while resuming
+ * from another devices (e.g. serial console). */
+ if (device_may_wakeup(&(pdev->dev)))
+ if (priv->wolenabled == PMT_SUPPORTED)
+ priv->mac_type->ops->pmt(dev->base_addr, 0);
+
+ netif_device_attach(dev);
+
+ /* Enable the MAC and DMA */
+ stmmac_mac_enable_rx(ioaddr);
+ stmmac_mac_enable_tx(ioaddr);
+ stmmac_dma_start_tx(ioaddr);
+ stmmac_dma_start_rx(ioaddr);
+
+#ifdef CONFIG_STMMAC_TIMER
+ priv->tm->timer_start(tmrate);
+#endif
+ napi_enable(&priv->napi);
+
+ if (priv->phydev)
+ phy_start(priv->phydev);
+
+ netif_start_queue(dev);
+
+out_resume:
+ spin_unlock(&priv->lock);
+ return 0;
+}
+#endif
+
+static struct platform_driver stmmac_driver = {
+ .driver = {
+ .name = STMMAC_RESOURCE_NAME,
+ },
+ .probe = stmmac_dvr_probe,
+ .remove = stmmac_dvr_remove,
+#ifdef CONFIG_PM
+ .suspend = stmmac_suspend,
+ .resume = stmmac_resume,
+#endif
+
+};
+
+/**
+ * stmmac_init_module - Entry point for the driver
+ * Description: This function is the entry point for the driver.
+ */
+static int __init stmmac_init_module(void)
+{
+ int ret;
+
+ if (platform_driver_register(&stmmacphy_driver)) {
+ pr_err("No PHY devices registered!\n");
+ return -ENODEV;
+ }
+
+ ret = platform_driver_register(&stmmac_driver);
+ return ret;
+}
+
+/**
+ * stmmac_cleanup_module - Cleanup routine for the driver
+ * Description: This function is the cleanup routine for the driver.
+ */
+static void __exit stmmac_cleanup_module(void)
+{
+ platform_driver_unregister(&stmmacphy_driver);
+ platform_driver_unregister(&stmmac_driver);
+}
+
+#ifndef MODULE
+static int __init stmmac_cmdline_opt(char *str)
+{
+ char *opt;
+
+ if (!str || !*str)
+ return -EINVAL;
+ while ((opt = strsep(&str, ",")) != NULL) {
+ if (!strncmp(opt, "debug:", 6))
+ strict_strtoul(opt + 6, 0, (unsigned long *)&debug);
+ else if (!strncmp(opt, "phyaddr:", 8))
+ strict_strtoul(opt + 8, 0, (unsigned long *)&phyaddr);
+ else if (!strncmp(opt, "dma_txsize:", 11))
+ strict_strtoul(opt + 11, 0,
+ (unsigned long *)&dma_txsize);
+ else if (!strncmp(opt, "dma_rxsize:", 11))
+ strict_strtoul(opt + 11, 0,
+ (unsigned long *)&dma_rxsize);
+ else if (!strncmp(opt, "buf_sz:", 7))
+ strict_strtoul(opt + 7, 0, (unsigned long *)&buf_sz);
+ else if (!strncmp(opt, "tc:", 3))
+ strict_strtoul(opt + 3, 0, (unsigned long *)&tc);
+ else if (!strncmp(opt, "tx_coe:", 7))
+ strict_strtoul(opt + 7, 0, (unsigned long *)&tx_coe);
+ else if (!strncmp(opt, "watchdog:", 9))
+ strict_strtoul(opt + 9, 0, (unsigned long *)&watchdog);
+ else if (!strncmp(opt, "flow_ctrl:", 10))
+ strict_strtoul(opt + 10, 0,
+ (unsigned long *)&flow_ctrl);
+ else if (!strncmp(opt, "pause:", 6))
+ strict_strtoul(opt + 6, 0, (unsigned long *)&pause);
+#ifdef CONFIG_STMMAC_TIMER
+ else if (!strncmp(opt, "tmrate:", 7))
+ strict_strtoul(opt + 7, 0, (unsigned long *)&tmrate);
+#endif
+ }
+ return 0;
+}
+
+__setup("stmmaceth=", stmmac_cmdline_opt);
+#endif
+
+module_init(stmmac_init_module);
+module_exit(stmmac_cleanup_module);
+
+MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet driver");
+MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/stmmac/stmmac_mdio.c b/drivers/net/stmmac/stmmac_mdio.c
new file mode 100644
index 000000000000..8498552a22fc
--- /dev/null
+++ b/drivers/net/stmmac/stmmac_mdio.c
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ STMMAC Ethernet Driver -- MDIO bus implementation
+ Provides Bus interface for MII registers
+
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Carl Shaw <carl.shaw@st.com>
+ Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/netdevice.h>
+#include <linux/mii.h>
+#include <linux/phy.h>
+
+#include "stmmac.h"
+
+#define MII_BUSY 0x00000001
+#define MII_WRITE 0x00000002
+
+/**
+ * stmmac_mdio_read
+ * @bus: points to the mii_bus structure
+ * @phyaddr: MII addr reg bits 15-11
+ * @phyreg: MII addr reg bits 10-6
+ * Description: it reads data from the MII register from within the phy device.
+ * For the 7111 GMAC, we must set the bit 0 in the MII address register while
+ * accessing the PHY registers.
+ * Fortunately, it seems this has no drawback for the 7109 MAC.
+ */
+static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg)
+{
+ struct net_device *ndev = bus->priv;
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ unsigned long ioaddr = ndev->base_addr;
+ unsigned int mii_address = priv->mac_type->hw.mii.addr;
+ unsigned int mii_data = priv->mac_type->hw.mii.data;
+
+ int data;
+ u16 regValue = (((phyaddr << 11) & (0x0000F800)) |
+ ((phyreg << 6) & (0x000007C0)));
+ regValue |= MII_BUSY; /* in case of GMAC */
+
+ do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
+ writel(regValue, ioaddr + mii_address);
+ do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
+
+ /* Read the data from the MII data register */
+ data = (int)readl(ioaddr + mii_data);
+
+ return data;
+}
+
+/**
+ * stmmac_mdio_write
+ * @bus: points to the mii_bus structure
+ * @phyaddr: MII addr reg bits 15-11
+ * @phyreg: MII addr reg bits 10-6
+ * @phydata: phy data
+ * Description: it writes the data into the MII register from within the device.
+ */
+static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg,
+ u16 phydata)
+{
+ struct net_device *ndev = bus->priv;
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ unsigned long ioaddr = ndev->base_addr;
+ unsigned int mii_address = priv->mac_type->hw.mii.addr;
+ unsigned int mii_data = priv->mac_type->hw.mii.data;
+
+ u16 value =
+ (((phyaddr << 11) & (0x0000F800)) | ((phyreg << 6) & (0x000007C0)))
+ | MII_WRITE;
+
+ value |= MII_BUSY;
+
+ /* Wait until any existing MII operation is complete */
+ do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
+
+ /* Set the MII address register to write */
+ writel(phydata, ioaddr + mii_data);
+ writel(value, ioaddr + mii_address);
+
+ /* Wait until any existing MII operation is complete */
+ do {} while (((readl(ioaddr + mii_address)) & MII_BUSY) == 1);
+
+ return 0;
+}
+
+/**
+ * stmmac_mdio_reset
+ * @bus: points to the mii_bus structure
+ * Description: reset the MII bus
+ */
+static int stmmac_mdio_reset(struct mii_bus *bus)
+{
+ struct net_device *ndev = bus->priv;
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ unsigned long ioaddr = ndev->base_addr;
+ unsigned int mii_address = priv->mac_type->hw.mii.addr;
+
+ if (priv->phy_reset) {
+ pr_debug("stmmac_mdio_reset: calling phy_reset\n");
+ priv->phy_reset(priv->bsp_priv);
+ }
+
+ /* This is a workaround for problems with the STE101P PHY.
+ * It doesn't complete its reset until at least one clock cycle
+ * on MDC, so perform a dummy mdio read.
+ */
+ writel(0, ioaddr + mii_address);
+
+ return 0;
+}
+
+/**
+ * stmmac_mdio_register
+ * @ndev: net device structure
+ * Description: it registers the MII bus
+ */
+int stmmac_mdio_register(struct net_device *ndev)
+{
+ int err = 0;
+ struct mii_bus *new_bus;
+ int *irqlist;
+ struct stmmac_priv *priv = netdev_priv(ndev);
+ int addr, found;
+
+ new_bus = mdiobus_alloc();
+ if (new_bus == NULL)
+ return -ENOMEM;
+
+ irqlist = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+ if (irqlist == NULL) {
+ err = -ENOMEM;
+ goto irqlist_alloc_fail;
+ }
+
+ /* Assign IRQ to phy at address phy_addr */
+ if (priv->phy_addr != -1)
+ irqlist[priv->phy_addr] = priv->phy_irq;
+
+ new_bus->name = "STMMAC MII Bus";
+ new_bus->read = &stmmac_mdio_read;
+ new_bus->write = &stmmac_mdio_write;
+ new_bus->reset = &stmmac_mdio_reset;
+ snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", priv->bus_id);
+ new_bus->priv = ndev;
+ new_bus->irq = irqlist;
+ new_bus->phy_mask = priv->phy_mask;
+ new_bus->parent = priv->device;
+ err = mdiobus_register(new_bus);
+ if (err != 0) {
+ pr_err("%s: Cannot register as MDIO bus\n", new_bus->name);
+ goto bus_register_fail;
+ }
+
+ priv->mii = new_bus;
+
+ found = 0;
+ for (addr = 0; addr < 32; addr++) {
+ struct phy_device *phydev = new_bus->phy_map[addr];
+ if (phydev) {
+ if (priv->phy_addr == -1) {
+ priv->phy_addr = addr;
+ phydev->irq = priv->phy_irq;
+ irqlist[addr] = priv->phy_irq;
+ }
+ pr_info("%s: PHY ID %08x at %d IRQ %d (%s)%s\n",
+ ndev->name, phydev->phy_id, addr,
+ phydev->irq, dev_name(&phydev->dev),
+ (addr == priv->phy_addr) ? " active" : "");
+ found = 1;
+ }
+ }
+
+ if (!found)
+ pr_warning("%s: No PHY found\n", ndev->name);
+
+ return 0;
+bus_register_fail:
+ kfree(irqlist);
+irqlist_alloc_fail:
+ kfree(new_bus);
+ return err;
+}
+
+/**
+ * stmmac_mdio_unregister
+ * @ndev: net device structure
+ * Description: it unregisters the MII bus
+ */
+int stmmac_mdio_unregister(struct net_device *ndev)
+{
+ struct stmmac_priv *priv = netdev_priv(ndev);
+
+ mdiobus_unregister(priv->mii);
+ priv->mii->priv = NULL;
+ kfree(priv->mii);
+
+ return 0;
+}
diff --git a/drivers/net/stmmac/stmmac_timer.c b/drivers/net/stmmac/stmmac_timer.c
new file mode 100644
index 000000000000..b838c6582077
--- /dev/null
+++ b/drivers/net/stmmac/stmmac_timer.c
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ STMMAC external timer support.
+
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/etherdevice.h>
+#include "stmmac_timer.h"
+
+static void stmmac_timer_handler(void *data)
+{
+ struct net_device *dev = (struct net_device *)data;
+
+ stmmac_schedule(dev);
+
+ return;
+}
+
+#define STMMAC_TIMER_MSG(timer, freq) \
+printk(KERN_INFO "stmmac_timer: %s Timer ON (freq %dHz)\n", timer, freq);
+
+#if defined(CONFIG_STMMAC_RTC_TIMER)
+#include <linux/rtc.h>
+static struct rtc_device *stmmac_rtc;
+static rtc_task_t stmmac_task;
+
+static void stmmac_rtc_start(unsigned int new_freq)
+{
+ rtc_irq_set_freq(stmmac_rtc, &stmmac_task, new_freq);
+ rtc_irq_set_state(stmmac_rtc, &stmmac_task, 1);
+ return;
+}
+
+static void stmmac_rtc_stop(void)
+{
+ rtc_irq_set_state(stmmac_rtc, &stmmac_task, 0);
+ return;
+}
+
+int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm)
+{
+ stmmac_task.private_data = dev;
+ stmmac_task.func = stmmac_timer_handler;
+
+ stmmac_rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+ if (stmmac_rtc == NULL) {
+ pr_error("open rtc device failed\n");
+ return -ENODEV;
+ }
+
+ rtc_irq_register(stmmac_rtc, &stmmac_task);
+
+ /* Periodic mode is not supported */
+ if ((rtc_irq_set_freq(stmmac_rtc, &stmmac_task, tm->freq) < 0)) {
+ pr_error("set periodic failed\n");
+ rtc_irq_unregister(stmmac_rtc, &stmmac_task);
+ rtc_class_close(stmmac_rtc);
+ return -1;
+ }
+
+ STMMAC_TIMER_MSG(CONFIG_RTC_HCTOSYS_DEVICE, tm->freq);
+
+ tm->timer_start = stmmac_rtc_start;
+ tm->timer_stop = stmmac_rtc_stop;
+
+ return 0;
+}
+
+int stmmac_close_ext_timer(void)
+{
+ rtc_irq_set_state(stmmac_rtc, &stmmac_task, 0);
+ rtc_irq_unregister(stmmac_rtc, &stmmac_task);
+ rtc_class_close(stmmac_rtc);
+ return 0;
+}
+
+#elif defined(CONFIG_STMMAC_TMU_TIMER)
+#include <linux/clk.h>
+#define TMU_CHANNEL "tmu2_clk"
+static struct clk *timer_clock;
+
+static void stmmac_tmu_start(unsigned int new_freq)
+{
+ clk_set_rate(timer_clock, new_freq);
+ clk_enable(timer_clock);
+ return;
+}
+
+static void stmmac_tmu_stop(void)
+{
+ clk_disable(timer_clock);
+ return;
+}
+
+int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm)
+{
+ timer_clock = clk_get(NULL, TMU_CHANNEL);
+
+ if (timer_clock == NULL)
+ return -1;
+
+ if (tmu2_register_user(stmmac_timer_handler, (void *)dev) < 0) {
+ timer_clock = NULL;
+ return -1;
+ }
+
+ STMMAC_TIMER_MSG("TMU2", tm->freq);
+ tm->timer_start = stmmac_tmu_start;
+ tm->timer_stop = stmmac_tmu_stop;
+
+ return 0;
+}
+
+int stmmac_close_ext_timer(void)
+{
+ clk_disable(timer_clock);
+ tmu2_unregister_user();
+ clk_put(timer_clock);
+ return 0;
+}
+#endif
diff --git a/drivers/net/stmmac/stmmac_timer.h b/drivers/net/stmmac/stmmac_timer.h
new file mode 100644
index 000000000000..f795cae33725
--- /dev/null
+++ b/drivers/net/stmmac/stmmac_timer.h
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ STMMAC external timer Header File.
+
+ Copyright (C) 2007-2009 STMicroelectronics Ltd
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
+ Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+*******************************************************************************/
+
+struct stmmac_timer {
+ void (*timer_start) (unsigned int new_freq);
+ void (*timer_stop) (void);
+ unsigned int freq;
+};
+
+/* Open the HW timer device and return 0 in case of success */
+int stmmac_open_ext_timer(struct net_device *dev, struct stmmac_timer *tm);
+/* Stop the timer and release it */
+int stmmac_close_ext_timer(void);
+/* Function used for scheduling task within the stmmac */
+void stmmac_schedule(struct net_device *dev);
+
+#if defined(CONFIG_STMMAC_TMU_TIMER)
+extern int tmu2_register_user(void *fnt, void *data);
+extern void tmu2_unregister_user(void);
+#endif
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 305ec3d783db..7019a0d1a82b 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -38,6 +38,7 @@
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/delay.h>
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/tg3.c b/drivers/net/tg3.c
index f09bc5dfe8b2..ba5d3fe753b6 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -902,11 +902,12 @@ static int tg3_mdio_read(struct mii_bus *bp, int mii_id, int reg)
struct tg3 *tp = bp->priv;
u32 val;
- if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED)
- return -EAGAIN;
+ spin_lock_bh(&tp->lock);
if (tg3_readphy(tp, reg, &val))
- return -EIO;
+ val = -EIO;
+
+ spin_unlock_bh(&tp->lock);
return val;
}
@@ -914,14 +915,16 @@ static int tg3_mdio_read(struct mii_bus *bp, int mii_id, int reg)
static int tg3_mdio_write(struct mii_bus *bp, int mii_id, int reg, u16 val)
{
struct tg3 *tp = bp->priv;
+ u32 ret = 0;
- if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_PAUSED)
- return -EAGAIN;
+ spin_lock_bh(&tp->lock);
if (tg3_writephy(tp, reg, val))
- return -EIO;
+ ret = -EIO;
- return 0;
+ spin_unlock_bh(&tp->lock);
+
+ return ret;
}
static int tg3_mdio_reset(struct mii_bus *bp)
@@ -1011,12 +1014,6 @@ static void tg3_mdio_config_5785(struct tg3 *tp)
static void tg3_mdio_start(struct tg3 *tp)
{
- if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
- mutex_lock(&tp->mdio_bus->mdio_lock);
- tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
- mutex_unlock(&tp->mdio_bus->mdio_lock);
- }
-
tp->mi_mode &= ~MAC_MI_MODE_AUTO_POLL;
tw32_f(MAC_MI_MODE, tp->mi_mode);
udelay(80);
@@ -1041,15 +1038,6 @@ static void tg3_mdio_start(struct tg3 *tp)
tg3_mdio_config_5785(tp);
}
-static void tg3_mdio_stop(struct tg3 *tp)
-{
- if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) {
- mutex_lock(&tp->mdio_bus->mdio_lock);
- tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_PAUSED;
- mutex_unlock(&tp->mdio_bus->mdio_lock);
- }
-}
-
static int tg3_mdio_init(struct tg3 *tp)
{
int i;
@@ -1141,7 +1129,6 @@ static void tg3_mdio_fini(struct tg3 *tp)
tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_INITED;
mdiobus_unregister(tp->mdio_bus);
mdiobus_free(tp->mdio_bus);
- tp->tg3_flags3 &= ~TG3_FLG3_MDIOBUS_PAUSED;
}
}
@@ -1363,7 +1350,7 @@ static void tg3_adjust_link(struct net_device *dev)
struct tg3 *tp = netdev_priv(dev);
struct phy_device *phydev = tp->mdio_bus->phy_map[PHY_ADDR];
- spin_lock(&tp->lock);
+ spin_lock_bh(&tp->lock);
mac_mode = tp->mac_mode & ~(MAC_MODE_PORT_MODE_MASK |
MAC_MODE_HALF_DUPLEX);
@@ -1431,7 +1418,7 @@ static void tg3_adjust_link(struct net_device *dev)
tp->link_config.active_speed = phydev->speed;
tp->link_config.active_duplex = phydev->duplex;
- spin_unlock(&tp->lock);
+ spin_unlock_bh(&tp->lock);
if (linkmesg)
tg3_link_report(tp);
@@ -6392,8 +6379,6 @@ static int tg3_chip_reset(struct tg3 *tp)
tg3_nvram_lock(tp);
- tg3_mdio_stop(tp);
-
tg3_ape_lock(tp, TG3_APE_LOCK_GRC);
/* No matching tg3_nvram_unlock() after this because
@@ -8698,6 +8683,8 @@ static int tg3_close(struct net_device *dev)
del_timer_sync(&tp->timer);
+ tg3_phy_stop(tp);
+
tg3_full_lock(tp, 1);
#if 0
tg3_dump_state(tp);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 524691cd9896..bab7940158e6 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2748,7 +2748,6 @@ struct tg3 {
#define TG3_FLG3_5701_DMA_BUG 0x00000008
#define TG3_FLG3_USE_PHYLIB 0x00000010
#define TG3_FLG3_MDIOBUS_INITED 0x00000020
-#define TG3_FLG3_MDIOBUS_PAUSED 0x00000040
#define TG3_FLG3_PHY_CONNECTED 0x00000080
#define TG3_FLG3_RGMII_STD_IBND_DISABLE 0x00000100
#define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200
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 525bbc5b9c9d..36cb2423bcf1 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -108,6 +108,7 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */
#define IBMTR_DEBUG_MESSAGES 0
#include <linux/module.h>
+#include <linux/sched.h>
#ifdef PCMCIA /* required for ibmtr_cs.c to build */
#undef MODULE /* yes, really */
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/typhoon.c b/drivers/net/typhoon.c
index d6d345229fe9..5921f5bdd764 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -108,6 +108,7 @@ static const int multicast_filter_limit = 32;
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
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/pegasus.c b/drivers/net/usb/pegasus.c
index 6fdaba8674b9..ed4a508ef262 100644
--- a/drivers/net/usb/pegasus.c
+++ b/drivers/net/usb/pegasus.c
@@ -62,8 +62,11 @@ static char *devid=NULL;
static struct usb_eth_dev usb_dev_id[] = {
#define PEGASUS_DEV(pn, vid, pid, flags) \
{.name = pn, .vendor = vid, .device = pid, .private = flags},
+#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \
+ PEGASUS_DEV(pn, vid, pid, flags)
#include "pegasus.h"
#undef PEGASUS_DEV
+#undef PEGASUS_DEV_CLASS
{NULL, 0, 0, 0},
{NULL, 0, 0, 0}
};
@@ -71,8 +74,18 @@ static struct usb_eth_dev usb_dev_id[] = {
static struct usb_device_id pegasus_ids[] = {
#define PEGASUS_DEV(pn, vid, pid, flags) \
{.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = vid, .idProduct = pid},
+/*
+ * The Belkin F8T012xx1 bluetooth adaptor has the same vendor and product
+ * IDs as the Belkin F5D5050, so we need to teach the pegasus driver to
+ * ignore adaptors belonging to the "Wireless" class 0xE0. For this one
+ * case anyway, seeing as the pegasus is for "Wired" adaptors.
+ */
+#define PEGASUS_DEV_CLASS(pn, vid, pid, dclass, flags) \
+ {.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_CLASS), \
+ .idVendor = vid, .idProduct = pid, .bDeviceClass = dclass},
#include "pegasus.h"
#undef PEGASUS_DEV
+#undef PEGASUS_DEV_CLASS
{},
{}
};
diff --git a/drivers/net/usb/pegasus.h b/drivers/net/usb/pegasus.h
index f968c834ff63..5d02f0200737 100644
--- a/drivers/net/usb/pegasus.h
+++ b/drivers/net/usb/pegasus.h
@@ -202,7 +202,11 @@ PEGASUS_DEV( "AEI USB Fast Ethernet Adapter", VENDOR_AEILAB, 0x1701,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Allied Telesyn Int. AT-USB100", VENDOR_ALLIEDTEL, 0xb100,
DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121,
+/*
+ * Distinguish between this Belkin adaptor and the Belkin bluetooth adaptors
+ * with the same product IDs by checking the device class too.
+ */
+PEGASUS_DEV_CLASS( "Belkin F5D5050 USB Ethernet", VENDOR_BELKIN, 0x0121, 0x00,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "Billionton USB-100", VENDOR_BILLIONTON, 0x0986,
DEFAULT_GPIO_RESET )
diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c
index d032bba9bc4c..0caa8008c51c 100644
--- a/drivers/net/usb/rndis_host.c
+++ b/drivers/net/usb/rndis_host.c
@@ -418,6 +418,7 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
goto halt_fail_and_release;
}
memcpy(net->dev_addr, bp, ETH_ALEN);
+ memcpy(net->perm_addr, bp, ETH_ALEN);
/* set a nonzero filter to enable data transfers */
memset(u.set, 0, sizeof *u.set);
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/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..0da5cd581cb6 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) {
diff --git a/drivers/net/vmxnet3/Makefile b/drivers/net/vmxnet3/Makefile
new file mode 100644
index 000000000000..880f5098eac9
--- /dev/null
+++ b/drivers/net/vmxnet3/Makefile
@@ -0,0 +1,35 @@
+################################################################################
+#
+# Linux driver for VMware's vmxnet3 ethernet NIC.
+#
+# Copyright (C) 2007-2009, VMware, Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License and no 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, GOOD TITLE or
+# NON INFRINGEMENT. See the GNU General Public License for more
+# details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
+# Maintained by: Shreyas Bhatewara <pv-drivers@vmware.com>
+#
+#
+################################################################################
+
+#
+# Makefile for the VMware vmxnet3 ethernet NIC driver
+#
+
+obj-$(CONFIG_VMXNET3) += vmxnet3.o
+
+vmxnet3-objs := vmxnet3_drv.o vmxnet3_ethtool.o
diff --git a/drivers/net/vmxnet3/upt1_defs.h b/drivers/net/vmxnet3/upt1_defs.h
new file mode 100644
index 000000000000..37108fb226d3
--- /dev/null
+++ b/drivers/net/vmxnet3/upt1_defs.h
@@ -0,0 +1,96 @@
+/*
+ * Linux driver for VMware's vmxnet3 ethernet NIC.
+ *
+ * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License and no 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Maintained by: Shreyas Bhatewara <pv-drivers@vmware.com>
+ *
+ */
+
+#ifndef _UPT1_DEFS_H
+#define _UPT1_DEFS_H
+
+struct UPT1_TxStats {
+ u64 TSOPktsTxOK; /* TSO pkts post-segmentation */
+ u64 TSOBytesTxOK;
+ u64 ucastPktsTxOK;
+ u64 ucastBytesTxOK;
+ u64 mcastPktsTxOK;
+ u64 mcastBytesTxOK;
+ u64 bcastPktsTxOK;
+ u64 bcastBytesTxOK;
+ u64 pktsTxError;
+ u64 pktsTxDiscard;
+};
+
+struct UPT1_RxStats {
+ u64 LROPktsRxOK; /* LRO pkts */
+ u64 LROBytesRxOK; /* bytes from LRO pkts */
+ /* the following counters are for pkts from the wire, i.e., pre-LRO */
+ u64 ucastPktsRxOK;
+ u64 ucastBytesRxOK;
+ u64 mcastPktsRxOK;
+ u64 mcastBytesRxOK;
+ u64 bcastPktsRxOK;
+ u64 bcastBytesRxOK;
+ u64 pktsRxOutOfBuf;
+ u64 pktsRxError;
+};
+
+/* interrupt moderation level */
+enum {
+ UPT1_IML_NONE = 0, /* no interrupt moderation */
+ UPT1_IML_HIGHEST = 7, /* least intr generated */
+ UPT1_IML_ADAPTIVE = 8, /* adpative intr moderation */
+};
+/* values for UPT1_RSSConf.hashFunc */
+enum {
+ UPT1_RSS_HASH_TYPE_NONE = 0x0,
+ UPT1_RSS_HASH_TYPE_IPV4 = 0x01,
+ UPT1_RSS_HASH_TYPE_TCP_IPV4 = 0x02,
+ UPT1_RSS_HASH_TYPE_IPV6 = 0x04,
+ UPT1_RSS_HASH_TYPE_TCP_IPV6 = 0x08,
+};
+
+enum {
+ UPT1_RSS_HASH_FUNC_NONE = 0x0,
+ UPT1_RSS_HASH_FUNC_TOEPLITZ = 0x01,
+};
+
+#define UPT1_RSS_MAX_KEY_SIZE 40
+#define UPT1_RSS_MAX_IND_TABLE_SIZE 128
+
+struct UPT1_RSSConf {
+ u16 hashType;
+ u16 hashFunc;
+ u16 hashKeySize;
+ u16 indTableSize;
+ u8 hashKey[UPT1_RSS_MAX_KEY_SIZE];
+ u8 indTable[UPT1_RSS_MAX_IND_TABLE_SIZE];
+};
+
+/* features */
+enum {
+ UPT1_F_RXCSUM = 0x0001, /* rx csum verification */
+ UPT1_F_RSS = 0x0002,
+ UPT1_F_RXVLAN = 0x0004, /* VLAN tag stripping */
+ UPT1_F_LRO = 0x0008,
+};
+#endif
diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h
new file mode 100644
index 000000000000..dc8ee4438a4f
--- /dev/null
+++ b/drivers/net/vmxnet3/vmxnet3_defs.h
@@ -0,0 +1,535 @@
+/*
+ * Linux driver for VMware's vmxnet3 ethernet NIC.
+ *
+ * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License and no 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Maintained by: Shreyas Bhatewara <pv-drivers@vmware.com>
+ *
+ */
+
+#ifndef _VMXNET3_DEFS_H_
+#define _VMXNET3_DEFS_H_
+
+#include "upt1_defs.h"
+
+/* all registers are 32 bit wide */
+/* BAR 1 */
+enum {
+ VMXNET3_REG_VRRS = 0x0, /* Vmxnet3 Revision Report Selection */
+ VMXNET3_REG_UVRS = 0x8, /* UPT Version Report Selection */
+ VMXNET3_REG_DSAL = 0x10, /* Driver Shared Address Low */
+ VMXNET3_REG_DSAH = 0x18, /* Driver Shared Address High */
+ VMXNET3_REG_CMD = 0x20, /* Command */
+ VMXNET3_REG_MACL = 0x28, /* MAC Address Low */
+ VMXNET3_REG_MACH = 0x30, /* MAC Address High */
+ VMXNET3_REG_ICR = 0x38, /* Interrupt Cause Register */
+ VMXNET3_REG_ECR = 0x40 /* Event Cause Register */
+};
+
+/* BAR 0 */
+enum {
+ VMXNET3_REG_IMR = 0x0, /* Interrupt Mask Register */
+ VMXNET3_REG_TXPROD = 0x600, /* Tx Producer Index */
+ VMXNET3_REG_RXPROD = 0x800, /* Rx Producer Index for ring 1 */
+ VMXNET3_REG_RXPROD2 = 0xA00 /* Rx Producer Index for ring 2 */
+};
+
+#define VMXNET3_PT_REG_SIZE 4096 /* BAR 0 */
+#define VMXNET3_VD_REG_SIZE 4096 /* BAR 1 */
+
+#define VMXNET3_REG_ALIGN 8 /* All registers are 8-byte aligned. */
+#define VMXNET3_REG_ALIGN_MASK 0x7
+
+/* I/O Mapped access to registers */
+#define VMXNET3_IO_TYPE_PT 0
+#define VMXNET3_IO_TYPE_VD 1
+#define VMXNET3_IO_ADDR(type, reg) (((type) << 24) | ((reg) & 0xFFFFFF))
+#define VMXNET3_IO_TYPE(addr) ((addr) >> 24)
+#define VMXNET3_IO_REG(addr) ((addr) & 0xFFFFFF)
+
+enum {
+ VMXNET3_CMD_FIRST_SET = 0xCAFE0000,
+ VMXNET3_CMD_ACTIVATE_DEV = VMXNET3_CMD_FIRST_SET,
+ VMXNET3_CMD_QUIESCE_DEV,
+ VMXNET3_CMD_RESET_DEV,
+ VMXNET3_CMD_UPDATE_RX_MODE,
+ VMXNET3_CMD_UPDATE_MAC_FILTERS,
+ VMXNET3_CMD_UPDATE_VLAN_FILTERS,
+ VMXNET3_CMD_UPDATE_RSSIDT,
+ VMXNET3_CMD_UPDATE_IML,
+ VMXNET3_CMD_UPDATE_PMCFG,
+ VMXNET3_CMD_UPDATE_FEATURE,
+ VMXNET3_CMD_LOAD_PLUGIN,
+
+ VMXNET3_CMD_FIRST_GET = 0xF00D0000,
+ VMXNET3_CMD_GET_QUEUE_STATUS = VMXNET3_CMD_FIRST_GET,
+ VMXNET3_CMD_GET_STATS,
+ VMXNET3_CMD_GET_LINK,
+ VMXNET3_CMD_GET_PERM_MAC_LO,
+ VMXNET3_CMD_GET_PERM_MAC_HI,
+ VMXNET3_CMD_GET_DID_LO,
+ VMXNET3_CMD_GET_DID_HI,
+ VMXNET3_CMD_GET_DEV_EXTRA_INFO,
+ VMXNET3_CMD_GET_CONF_INTR
+};
+
+struct Vmxnet3_TxDesc {
+ u64 addr;
+
+ u32 len:14;
+ u32 gen:1; /* generation bit */
+ u32 rsvd:1;
+ u32 dtype:1; /* descriptor type */
+ u32 ext1:1;
+ u32 msscof:14; /* MSS, checksum offset, flags */
+
+ u32 hlen:10; /* header len */
+ u32 om:2; /* offload mode */
+ u32 eop:1; /* End Of Packet */
+ u32 cq:1; /* completion request */
+ u32 ext2:1;
+ u32 ti:1; /* VLAN Tag Insertion */
+ u32 tci:16; /* Tag to Insert */
+};
+
+/* TxDesc.OM values */
+#define VMXNET3_OM_NONE 0
+#define VMXNET3_OM_CSUM 2
+#define VMXNET3_OM_TSO 3
+
+/* fields in TxDesc we access w/o using bit fields */
+#define VMXNET3_TXD_EOP_SHIFT 12
+#define VMXNET3_TXD_CQ_SHIFT 13
+#define VMXNET3_TXD_GEN_SHIFT 14
+
+#define VMXNET3_TXD_CQ (1 << VMXNET3_TXD_CQ_SHIFT)
+#define VMXNET3_TXD_EOP (1 << VMXNET3_TXD_EOP_SHIFT)
+#define VMXNET3_TXD_GEN (1 << VMXNET3_TXD_GEN_SHIFT)
+
+#define VMXNET3_HDR_COPY_SIZE 128
+
+
+struct Vmxnet3_TxDataDesc {
+ u8 data[VMXNET3_HDR_COPY_SIZE];
+};
+
+
+struct Vmxnet3_TxCompDesc {
+ u32 txdIdx:12; /* Index of the EOP TxDesc */
+ u32 ext1:20;
+
+ u32 ext2;
+ u32 ext3;
+
+ u32 rsvd:24;
+ u32 type:7; /* completion type */
+ u32 gen:1; /* generation bit */
+};
+
+
+struct Vmxnet3_RxDesc {
+ u64 addr;
+
+ u32 len:14;
+ u32 btype:1; /* Buffer Type */
+ u32 dtype:1; /* Descriptor type */
+ u32 rsvd:15;
+ u32 gen:1; /* Generation bit */
+
+ u32 ext1;
+};
+
+/* values of RXD.BTYPE */
+#define VMXNET3_RXD_BTYPE_HEAD 0 /* head only */
+#define VMXNET3_RXD_BTYPE_BODY 1 /* body only */
+
+/* fields in RxDesc we access w/o using bit fields */
+#define VMXNET3_RXD_BTYPE_SHIFT 14
+#define VMXNET3_RXD_GEN_SHIFT 31
+
+
+struct Vmxnet3_RxCompDesc {
+ u32 rxdIdx:12; /* Index of the RxDesc */
+ u32 ext1:2;
+ u32 eop:1; /* End of Packet */
+ u32 sop:1; /* Start of Packet */
+ u32 rqID:10; /* rx queue/ring ID */
+ u32 rssType:4; /* RSS hash type used */
+ u32 cnc:1; /* Checksum Not Calculated */
+ u32 ext2:1;
+
+ u32 rssHash; /* RSS hash value */
+
+ u32 len:14; /* data length */
+ u32 err:1; /* Error */
+ u32 ts:1; /* Tag is stripped */
+ u32 tci:16; /* Tag stripped */
+
+ u32 csum:16;
+ u32 tuc:1; /* TCP/UDP Checksum Correct */
+ u32 udp:1; /* UDP packet */
+ u32 tcp:1; /* TCP packet */
+ u32 ipc:1; /* IP Checksum Correct */
+ u32 v6:1; /* IPv6 */
+ u32 v4:1; /* IPv4 */
+ u32 frg:1; /* IP Fragment */
+ u32 fcs:1; /* Frame CRC correct */
+ u32 type:7; /* completion type */
+ u32 gen:1; /* generation bit */
+};
+
+/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */
+#define VMXNET3_RCD_TUC_SHIFT 16
+#define VMXNET3_RCD_IPC_SHIFT 19
+
+/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.qword[1] */
+#define VMXNET3_RCD_TYPE_SHIFT 56
+#define VMXNET3_RCD_GEN_SHIFT 63
+
+/* csum OK for TCP/UDP pkts over IP */
+#define VMXNET3_RCD_CSUM_OK (1 << VMXNET3_RCD_TUC_SHIFT | \
+ 1 << VMXNET3_RCD_IPC_SHIFT)
+
+/* value of RxCompDesc.rssType */
+enum {
+ VMXNET3_RCD_RSS_TYPE_NONE = 0,
+ VMXNET3_RCD_RSS_TYPE_IPV4 = 1,
+ VMXNET3_RCD_RSS_TYPE_TCPIPV4 = 2,
+ VMXNET3_RCD_RSS_TYPE_IPV6 = 3,
+ VMXNET3_RCD_RSS_TYPE_TCPIPV6 = 4,
+};
+
+
+/* a union for accessing all cmd/completion descriptors */
+union Vmxnet3_GenericDesc {
+ u64 qword[2];
+ u32 dword[4];
+ u16 word[8];
+ struct Vmxnet3_TxDesc txd;
+ struct Vmxnet3_RxDesc rxd;
+ struct Vmxnet3_TxCompDesc tcd;
+ struct Vmxnet3_RxCompDesc rcd;
+};
+
+#define VMXNET3_INIT_GEN 1
+
+/* Max size of a single tx buffer */
+#define VMXNET3_MAX_TX_BUF_SIZE (1 << 14)
+
+/* # of tx desc needed for a tx buffer size */
+#define VMXNET3_TXD_NEEDED(size) (((size) + VMXNET3_MAX_TX_BUF_SIZE - 1) / \
+ VMXNET3_MAX_TX_BUF_SIZE)
+
+/* max # of tx descs for a non-tso pkt */
+#define VMXNET3_MAX_TXD_PER_PKT 16
+
+/* Max size of a single rx buffer */
+#define VMXNET3_MAX_RX_BUF_SIZE ((1 << 14) - 1)
+/* Minimum size of a type 0 buffer */
+#define VMXNET3_MIN_T0_BUF_SIZE 128
+#define VMXNET3_MAX_CSUM_OFFSET 1024
+
+/* Ring base address alignment */
+#define VMXNET3_RING_BA_ALIGN 512
+#define VMXNET3_RING_BA_MASK (VMXNET3_RING_BA_ALIGN - 1)
+
+/* Ring size must be a multiple of 32 */
+#define VMXNET3_RING_SIZE_ALIGN 32
+#define VMXNET3_RING_SIZE_MASK (VMXNET3_RING_SIZE_ALIGN - 1)
+
+/* Max ring size */
+#define VMXNET3_TX_RING_MAX_SIZE 4096
+#define VMXNET3_TC_RING_MAX_SIZE 4096
+#define VMXNET3_RX_RING_MAX_SIZE 4096
+#define VMXNET3_RC_RING_MAX_SIZE 8192
+
+/* a list of reasons for queue stop */
+
+enum {
+ VMXNET3_ERR_NOEOP = 0x80000000, /* cannot find the EOP desc of a pkt */
+ VMXNET3_ERR_TXD_REUSE = 0x80000001, /* reuse TxDesc before tx completion */
+ VMXNET3_ERR_BIG_PKT = 0x80000002, /* too many TxDesc for a pkt */
+ VMXNET3_ERR_DESC_NOT_SPT = 0x80000003, /* descriptor type not supported */
+ VMXNET3_ERR_SMALL_BUF = 0x80000004, /* type 0 buffer too small */
+ VMXNET3_ERR_STRESS = 0x80000005, /* stress option firing in vmkernel */
+ VMXNET3_ERR_SWITCH = 0x80000006, /* mode switch failure */
+ VMXNET3_ERR_TXD_INVALID = 0x80000007, /* invalid TxDesc */
+};
+
+/* completion descriptor types */
+#define VMXNET3_CDTYPE_TXCOMP 0 /* Tx Completion Descriptor */
+#define VMXNET3_CDTYPE_RXCOMP 3 /* Rx Completion Descriptor */
+
+enum {
+ VMXNET3_GOS_BITS_UNK = 0, /* unknown */
+ VMXNET3_GOS_BITS_32 = 1,
+ VMXNET3_GOS_BITS_64 = 2,
+};
+
+#define VMXNET3_GOS_TYPE_LINUX 1
+
+
+struct Vmxnet3_GOSInfo {
+ u32 gosBits:2; /* 32-bit or 64-bit? */
+ u32 gosType:4; /* which guest */
+ u32 gosVer:16; /* gos version */
+ u32 gosMisc:10; /* other info about gos */
+};
+
+
+struct Vmxnet3_DriverInfo {
+ u32 version;
+ struct Vmxnet3_GOSInfo gos;
+ u32 vmxnet3RevSpt;
+ u32 uptVerSpt;
+};
+
+
+#define VMXNET3_REV1_MAGIC 0xbabefee1
+
+/*
+ * QueueDescPA must be 128 bytes aligned. It points to an array of
+ * Vmxnet3_TxQueueDesc followed by an array of Vmxnet3_RxQueueDesc.
+ * The number of Vmxnet3_TxQueueDesc/Vmxnet3_RxQueueDesc are specified by
+ * Vmxnet3_MiscConf.numTxQueues/numRxQueues, respectively.
+ */
+#define VMXNET3_QUEUE_DESC_ALIGN 128
+
+
+struct Vmxnet3_MiscConf {
+ struct Vmxnet3_DriverInfo driverInfo;
+ u64 uptFeatures;
+ u64 ddPA; /* driver data PA */
+ u64 queueDescPA; /* queue descriptor table PA */
+ u32 ddLen; /* driver data len */
+ u32 queueDescLen; /* queue desc. table len in bytes */
+ u32 mtu;
+ u16 maxNumRxSG;
+ u8 numTxQueues;
+ u8 numRxQueues;
+ u32 reserved[4];
+};
+
+
+struct Vmxnet3_TxQueueConf {
+ u64 txRingBasePA;
+ u64 dataRingBasePA;
+ u64 compRingBasePA;
+ u64 ddPA; /* driver data */
+ u64 reserved;
+ u32 txRingSize; /* # of tx desc */
+ u32 dataRingSize; /* # of data desc */
+ u32 compRingSize; /* # of comp desc */
+ u32 ddLen; /* size of driver data */
+ u8 intrIdx;
+ u8 _pad[7];
+};
+
+
+struct Vmxnet3_RxQueueConf {
+ u64 rxRingBasePA[2];
+ u64 compRingBasePA;
+ u64 ddPA; /* driver data */
+ u64 reserved;
+ u32 rxRingSize[2]; /* # of rx desc */
+ u32 compRingSize; /* # of rx comp desc */
+ u32 ddLen; /* size of driver data */
+ u8 intrIdx;
+ u8 _pad[7];
+};
+
+
+enum vmxnet3_intr_mask_mode {
+ VMXNET3_IMM_AUTO = 0,
+ VMXNET3_IMM_ACTIVE = 1,
+ VMXNET3_IMM_LAZY = 2
+};
+
+enum vmxnet3_intr_type {
+ VMXNET3_IT_AUTO = 0,
+ VMXNET3_IT_INTX = 1,
+ VMXNET3_IT_MSI = 2,
+ VMXNET3_IT_MSIX = 3
+};
+
+#define VMXNET3_MAX_TX_QUEUES 8
+#define VMXNET3_MAX_RX_QUEUES 16
+/* addition 1 for events */
+#define VMXNET3_MAX_INTRS 25
+
+
+struct Vmxnet3_IntrConf {
+ bool autoMask;
+ u8 numIntrs; /* # of interrupts */
+ u8 eventIntrIdx;
+ u8 modLevels[VMXNET3_MAX_INTRS]; /* moderation level for
+ * each intr */
+ u32 reserved[3];
+};
+
+/* one bit per VLAN ID, the size is in the units of u32 */
+#define VMXNET3_VFT_SIZE (4096 / (sizeof(u32) * 8))
+
+
+struct Vmxnet3_QueueStatus {
+ bool stopped;
+ u8 _pad[3];
+ u32 error;
+};
+
+
+struct Vmxnet3_TxQueueCtrl {
+ u32 txNumDeferred;
+ u32 txThreshold;
+ u64 reserved;
+};
+
+
+struct Vmxnet3_RxQueueCtrl {
+ bool updateRxProd;
+ u8 _pad[7];
+ u64 reserved;
+};
+
+enum {
+ VMXNET3_RXM_UCAST = 0x01, /* unicast only */
+ VMXNET3_RXM_MCAST = 0x02, /* multicast passing the filters */
+ VMXNET3_RXM_BCAST = 0x04, /* broadcast only */
+ VMXNET3_RXM_ALL_MULTI = 0x08, /* all multicast */
+ VMXNET3_RXM_PROMISC = 0x10 /* promiscuous */
+};
+
+struct Vmxnet3_RxFilterConf {
+ u32 rxMode; /* VMXNET3_RXM_xxx */
+ u16 mfTableLen; /* size of the multicast filter table */
+ u16 _pad1;
+ u64 mfTablePA; /* PA of the multicast filters table */
+ u32 vfTable[VMXNET3_VFT_SIZE]; /* vlan filter */
+};
+
+
+#define VMXNET3_PM_MAX_FILTERS 6
+#define VMXNET3_PM_MAX_PATTERN_SIZE 128
+#define VMXNET3_PM_MAX_MASK_SIZE (VMXNET3_PM_MAX_PATTERN_SIZE / 8)
+
+#define VMXNET3_PM_WAKEUP_MAGIC 0x01 /* wake up on magic pkts */
+#define VMXNET3_PM_WAKEUP_FILTER 0x02 /* wake up on pkts matching
+ * filters */
+
+
+struct Vmxnet3_PM_PktFilter {
+ u8 maskSize;
+ u8 patternSize;
+ u8 mask[VMXNET3_PM_MAX_MASK_SIZE];
+ u8 pattern[VMXNET3_PM_MAX_PATTERN_SIZE];
+ u8 pad[6];
+};
+
+
+struct Vmxnet3_PMConf {
+ u16 wakeUpEvents; /* VMXNET3_PM_WAKEUP_xxx */
+ u8 numFilters;
+ u8 pad[5];
+ struct Vmxnet3_PM_PktFilter filters[VMXNET3_PM_MAX_FILTERS];
+};
+
+
+struct Vmxnet3_VariableLenConfDesc {
+ u32 confVer;
+ u32 confLen;
+ u64 confPA;
+};
+
+
+struct Vmxnet3_TxQueueDesc {
+ struct Vmxnet3_TxQueueCtrl ctrl;
+ struct Vmxnet3_TxQueueConf conf;
+
+ /* Driver read after a GET command */
+ struct Vmxnet3_QueueStatus status;
+ struct UPT1_TxStats stats;
+ u8 _pad[88]; /* 128 aligned */
+};
+
+
+struct Vmxnet3_RxQueueDesc {
+ struct Vmxnet3_RxQueueCtrl ctrl;
+ struct Vmxnet3_RxQueueConf conf;
+ /* Driver read after a GET commad */
+ struct Vmxnet3_QueueStatus status;
+ struct UPT1_RxStats stats;
+ u8 __pad[88]; /* 128 aligned */
+};
+
+
+struct Vmxnet3_DSDevRead {
+ /* read-only region for device, read by dev in response to a SET cmd */
+ struct Vmxnet3_MiscConf misc;
+ struct Vmxnet3_IntrConf intrConf;
+ struct Vmxnet3_RxFilterConf rxFilterConf;
+ struct Vmxnet3_VariableLenConfDesc rssConfDesc;
+ struct Vmxnet3_VariableLenConfDesc pmConfDesc;
+ struct Vmxnet3_VariableLenConfDesc pluginConfDesc;
+};
+
+/* All structures in DriverShared are padded to multiples of 8 bytes */
+struct Vmxnet3_DriverShared {
+ u32 magic;
+ /* make devRead start at 64bit boundaries */
+ u32 pad;
+ struct Vmxnet3_DSDevRead devRead;
+ u32 ecr;
+ u32 reserved[5];
+};
+
+
+#define VMXNET3_ECR_RQERR (1 << 0)
+#define VMXNET3_ECR_TQERR (1 << 1)
+#define VMXNET3_ECR_LINK (1 << 2)
+#define VMXNET3_ECR_DIC (1 << 3)
+#define VMXNET3_ECR_DEBUG (1 << 4)
+
+/* flip the gen bit of a ring */
+#define VMXNET3_FLIP_RING_GEN(gen) ((gen) = (gen) ^ 0x1)
+
+/* only use this if moving the idx won't affect the gen bit */
+#define VMXNET3_INC_RING_IDX_ONLY(idx, ring_size) \
+ do {\
+ (idx)++;\
+ if (unlikely((idx) == (ring_size))) {\
+ (idx) = 0;\
+ } \
+ } while (0)
+
+#define VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid) \
+ (vfTable[vid >> 5] |= (1 << (vid & 31)))
+#define VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid) \
+ (vfTable[vid >> 5] &= ~(1 << (vid & 31)))
+
+#define VMXNET3_VFTABLE_ENTRY_IS_SET(vfTable, vid) \
+ ((vfTable[vid >> 5] & (1 << (vid & 31))) != 0)
+
+#define VMXNET3_MAX_MTU 9000
+#define VMXNET3_MIN_MTU 60
+
+#define VMXNET3_LINK_UP (10000 << 16 | 1) /* 10 Gbps, up */
+#define VMXNET3_LINK_DOWN 0
+
+#endif /* _VMXNET3_DEFS_H_ */
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
new file mode 100644
index 000000000000..6a16f76f277e
--- /dev/null
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -0,0 +1,2565 @@
+/*
+ * Linux driver for VMware's vmxnet3 ethernet NIC.
+ *
+ * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License and no 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Maintained by: Shreyas Bhatewara <pv-drivers@vmware.com>
+ *
+ */
+
+#include "vmxnet3_int.h"
+
+char vmxnet3_driver_name[] = "vmxnet3";
+#define VMXNET3_DRIVER_DESC "VMware vmxnet3 virtual NIC driver"
+
+
+/*
+ * PCI Device ID Table
+ * Last entry must be all 0s
+ */
+static const struct pci_device_id vmxnet3_pciid_table[] = {
+ {PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_VMXNET3)},
+ {0}
+};
+
+MODULE_DEVICE_TABLE(pci, vmxnet3_pciid_table);
+
+static atomic_t devices_found;
+
+
+/*
+ * Enable/Disable the given intr
+ */
+static void
+vmxnet3_enable_intr(struct vmxnet3_adapter *adapter, unsigned intr_idx)
+{
+ VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_IMR + intr_idx * 8, 0);
+}
+
+
+static void
+vmxnet3_disable_intr(struct vmxnet3_adapter *adapter, unsigned intr_idx)
+{
+ VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_IMR + intr_idx * 8, 1);
+}
+
+
+/*
+ * Enable/Disable all intrs used by the device
+ */
+static void
+vmxnet3_enable_all_intrs(struct vmxnet3_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->intr.num_intrs; i++)
+ vmxnet3_enable_intr(adapter, i);
+}
+
+
+static void
+vmxnet3_disable_all_intrs(struct vmxnet3_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->intr.num_intrs; i++)
+ vmxnet3_disable_intr(adapter, i);
+}
+
+
+static void
+vmxnet3_ack_events(struct vmxnet3_adapter *adapter, u32 events)
+{
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_ECR, events);
+}
+
+
+static bool
+vmxnet3_tq_stopped(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
+{
+ return netif_queue_stopped(adapter->netdev);
+}
+
+
+static void
+vmxnet3_tq_start(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
+{
+ tq->stopped = false;
+ netif_start_queue(adapter->netdev);
+}
+
+
+static void
+vmxnet3_tq_wake(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
+{
+ tq->stopped = false;
+ netif_wake_queue(adapter->netdev);
+}
+
+
+static void
+vmxnet3_tq_stop(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
+{
+ tq->stopped = true;
+ tq->num_stop++;
+ netif_stop_queue(adapter->netdev);
+}
+
+
+/*
+ * Check the link state. This may start or stop the tx queue.
+ */
+static void
+vmxnet3_check_link(struct vmxnet3_adapter *adapter)
+{
+ u32 ret;
+
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_LINK);
+ ret = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+ adapter->link_speed = ret >> 16;
+ if (ret & 1) { /* Link is up. */
+ printk(KERN_INFO "%s: NIC Link is Up %d Mbps\n",
+ adapter->netdev->name, adapter->link_speed);
+ if (!netif_carrier_ok(adapter->netdev))
+ netif_carrier_on(adapter->netdev);
+
+ vmxnet3_tq_start(&adapter->tx_queue, adapter);
+ } else {
+ printk(KERN_INFO "%s: NIC Link is Down\n",
+ adapter->netdev->name);
+ if (netif_carrier_ok(adapter->netdev))
+ netif_carrier_off(adapter->netdev);
+
+ vmxnet3_tq_stop(&adapter->tx_queue, adapter);
+ }
+}
+
+
+static void
+vmxnet3_process_events(struct vmxnet3_adapter *adapter)
+{
+ u32 events = adapter->shared->ecr;
+ if (!events)
+ return;
+
+ vmxnet3_ack_events(adapter, events);
+
+ /* Check if link state has changed */
+ if (events & VMXNET3_ECR_LINK)
+ vmxnet3_check_link(adapter);
+
+ /* Check if there is an error on xmit/recv queues */
+ if (events & (VMXNET3_ECR_TQERR | VMXNET3_ECR_RQERR)) {
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_GET_QUEUE_STATUS);
+
+ if (adapter->tqd_start->status.stopped) {
+ printk(KERN_ERR "%s: tq error 0x%x\n",
+ adapter->netdev->name,
+ adapter->tqd_start->status.error);
+ }
+ if (adapter->rqd_start->status.stopped) {
+ printk(KERN_ERR "%s: rq error 0x%x\n",
+ adapter->netdev->name,
+ adapter->rqd_start->status.error);
+ }
+
+ schedule_work(&adapter->work);
+ }
+}
+
+
+static void
+vmxnet3_unmap_tx_buf(struct vmxnet3_tx_buf_info *tbi,
+ struct pci_dev *pdev)
+{
+ if (tbi->map_type == VMXNET3_MAP_SINGLE)
+ pci_unmap_single(pdev, tbi->dma_addr, tbi->len,
+ PCI_DMA_TODEVICE);
+ else if (tbi->map_type == VMXNET3_MAP_PAGE)
+ pci_unmap_page(pdev, tbi->dma_addr, tbi->len,
+ PCI_DMA_TODEVICE);
+ else
+ BUG_ON(tbi->map_type != VMXNET3_MAP_NONE);
+
+ tbi->map_type = VMXNET3_MAP_NONE; /* to help debugging */
+}
+
+
+static int
+vmxnet3_unmap_pkt(u32 eop_idx, struct vmxnet3_tx_queue *tq,
+ struct pci_dev *pdev, struct vmxnet3_adapter *adapter)
+{
+ struct sk_buff *skb;
+ int entries = 0;
+
+ /* no out of order completion */
+ BUG_ON(tq->buf_info[eop_idx].sop_idx != tq->tx_ring.next2comp);
+ BUG_ON(tq->tx_ring.base[eop_idx].txd.eop != 1);
+
+ skb = tq->buf_info[eop_idx].skb;
+ BUG_ON(skb == NULL);
+ tq->buf_info[eop_idx].skb = NULL;
+
+ VMXNET3_INC_RING_IDX_ONLY(eop_idx, tq->tx_ring.size);
+
+ while (tq->tx_ring.next2comp != eop_idx) {
+ vmxnet3_unmap_tx_buf(tq->buf_info + tq->tx_ring.next2comp,
+ pdev);
+
+ /* update next2comp w/o tx_lock. Since we are marking more,
+ * instead of less, tx ring entries avail, the worst case is
+ * that the tx routine incorrectly re-queues a pkt due to
+ * insufficient tx ring entries.
+ */
+ vmxnet3_cmd_ring_adv_next2comp(&tq->tx_ring);
+ entries++;
+ }
+
+ dev_kfree_skb_any(skb);
+ return entries;
+}
+
+
+static int
+vmxnet3_tq_tx_complete(struct vmxnet3_tx_queue *tq,
+ struct vmxnet3_adapter *adapter)
+{
+ int completed = 0;
+ union Vmxnet3_GenericDesc *gdesc;
+
+ gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
+ while (gdesc->tcd.gen == tq->comp_ring.gen) {
+ completed += vmxnet3_unmap_pkt(gdesc->tcd.txdIdx, tq,
+ adapter->pdev, adapter);
+
+ vmxnet3_comp_ring_adv_next2proc(&tq->comp_ring);
+ gdesc = tq->comp_ring.base + tq->comp_ring.next2proc;
+ }
+
+ if (completed) {
+ spin_lock(&tq->tx_lock);
+ if (unlikely(vmxnet3_tq_stopped(tq, adapter) &&
+ vmxnet3_cmd_ring_desc_avail(&tq->tx_ring) >
+ VMXNET3_WAKE_QUEUE_THRESHOLD(tq) &&
+ netif_carrier_ok(adapter->netdev))) {
+ vmxnet3_tq_wake(tq, adapter);
+ }
+ spin_unlock(&tq->tx_lock);
+ }
+ return completed;
+}
+
+
+static void
+vmxnet3_tq_cleanup(struct vmxnet3_tx_queue *tq,
+ struct vmxnet3_adapter *adapter)
+{
+ int i;
+
+ while (tq->tx_ring.next2comp != tq->tx_ring.next2fill) {
+ struct vmxnet3_tx_buf_info *tbi;
+ union Vmxnet3_GenericDesc *gdesc;
+
+ tbi = tq->buf_info + tq->tx_ring.next2comp;
+ gdesc = tq->tx_ring.base + tq->tx_ring.next2comp;
+
+ vmxnet3_unmap_tx_buf(tbi, adapter->pdev);
+ if (tbi->skb) {
+ dev_kfree_skb_any(tbi->skb);
+ tbi->skb = NULL;
+ }
+ vmxnet3_cmd_ring_adv_next2comp(&tq->tx_ring);
+ }
+
+ /* sanity check, verify all buffers are indeed unmapped and freed */
+ for (i = 0; i < tq->tx_ring.size; i++) {
+ BUG_ON(tq->buf_info[i].skb != NULL ||
+ tq->buf_info[i].map_type != VMXNET3_MAP_NONE);
+ }
+
+ tq->tx_ring.gen = VMXNET3_INIT_GEN;
+ tq->tx_ring.next2fill = tq->tx_ring.next2comp = 0;
+
+ tq->comp_ring.gen = VMXNET3_INIT_GEN;
+ tq->comp_ring.next2proc = 0;
+}
+
+
+void
+vmxnet3_tq_destroy(struct vmxnet3_tx_queue *tq,
+ struct vmxnet3_adapter *adapter)
+{
+ if (tq->tx_ring.base) {
+ pci_free_consistent(adapter->pdev, tq->tx_ring.size *
+ sizeof(struct Vmxnet3_TxDesc),
+ tq->tx_ring.base, tq->tx_ring.basePA);
+ tq->tx_ring.base = NULL;
+ }
+ if (tq->data_ring.base) {
+ pci_free_consistent(adapter->pdev, tq->data_ring.size *
+ sizeof(struct Vmxnet3_TxDataDesc),
+ tq->data_ring.base, tq->data_ring.basePA);
+ tq->data_ring.base = NULL;
+ }
+ if (tq->comp_ring.base) {
+ pci_free_consistent(adapter->pdev, tq->comp_ring.size *
+ sizeof(struct Vmxnet3_TxCompDesc),
+ tq->comp_ring.base, tq->comp_ring.basePA);
+ tq->comp_ring.base = NULL;
+ }
+ kfree(tq->buf_info);
+ tq->buf_info = NULL;
+}
+
+
+static void
+vmxnet3_tq_init(struct vmxnet3_tx_queue *tq,
+ struct vmxnet3_adapter *adapter)
+{
+ int i;
+
+ /* reset the tx ring contents to 0 and reset the tx ring states */
+ memset(tq->tx_ring.base, 0, tq->tx_ring.size *
+ sizeof(struct Vmxnet3_TxDesc));
+ tq->tx_ring.next2fill = tq->tx_ring.next2comp = 0;
+ tq->tx_ring.gen = VMXNET3_INIT_GEN;
+
+ memset(tq->data_ring.base, 0, tq->data_ring.size *
+ sizeof(struct Vmxnet3_TxDataDesc));
+
+ /* reset the tx comp ring contents to 0 and reset comp ring states */
+ memset(tq->comp_ring.base, 0, tq->comp_ring.size *
+ sizeof(struct Vmxnet3_TxCompDesc));
+ tq->comp_ring.next2proc = 0;
+ tq->comp_ring.gen = VMXNET3_INIT_GEN;
+
+ /* reset the bookkeeping data */
+ memset(tq->buf_info, 0, sizeof(tq->buf_info[0]) * tq->tx_ring.size);
+ for (i = 0; i < tq->tx_ring.size; i++)
+ tq->buf_info[i].map_type = VMXNET3_MAP_NONE;
+
+ /* stats are not reset */
+}
+
+
+static int
+vmxnet3_tq_create(struct vmxnet3_tx_queue *tq,
+ struct vmxnet3_adapter *adapter)
+{
+ BUG_ON(tq->tx_ring.base || tq->data_ring.base ||
+ tq->comp_ring.base || tq->buf_info);
+
+ tq->tx_ring.base = pci_alloc_consistent(adapter->pdev, tq->tx_ring.size
+ * sizeof(struct Vmxnet3_TxDesc),
+ &tq->tx_ring.basePA);
+ if (!tq->tx_ring.base) {
+ printk(KERN_ERR "%s: failed to allocate tx ring\n",
+ adapter->netdev->name);
+ goto err;
+ }
+
+ tq->data_ring.base = pci_alloc_consistent(adapter->pdev,
+ tq->data_ring.size *
+ sizeof(struct Vmxnet3_TxDataDesc),
+ &tq->data_ring.basePA);
+ if (!tq->data_ring.base) {
+ printk(KERN_ERR "%s: failed to allocate data ring\n",
+ adapter->netdev->name);
+ goto err;
+ }
+
+ tq->comp_ring.base = pci_alloc_consistent(adapter->pdev,
+ tq->comp_ring.size *
+ sizeof(struct Vmxnet3_TxCompDesc),
+ &tq->comp_ring.basePA);
+ if (!tq->comp_ring.base) {
+ printk(KERN_ERR "%s: failed to allocate tx comp ring\n",
+ adapter->netdev->name);
+ goto err;
+ }
+
+ tq->buf_info = kcalloc(tq->tx_ring.size, sizeof(tq->buf_info[0]),
+ GFP_KERNEL);
+ if (!tq->buf_info) {
+ printk(KERN_ERR "%s: failed to allocate tx bufinfo\n",
+ adapter->netdev->name);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ vmxnet3_tq_destroy(tq, adapter);
+ return -ENOMEM;
+}
+
+
+/*
+ * starting from ring->next2fill, allocate rx buffers for the given ring
+ * of the rx queue and update the rx desc. stop after @num_to_alloc buffers
+ * are allocated or allocation fails
+ */
+
+static int
+vmxnet3_rq_alloc_rx_buf(struct vmxnet3_rx_queue *rq, u32 ring_idx,
+ int num_to_alloc, struct vmxnet3_adapter *adapter)
+{
+ int num_allocated = 0;
+ struct vmxnet3_rx_buf_info *rbi_base = rq->buf_info[ring_idx];
+ struct vmxnet3_cmd_ring *ring = &rq->rx_ring[ring_idx];
+ u32 val;
+
+ while (num_allocated < num_to_alloc) {
+ struct vmxnet3_rx_buf_info *rbi;
+ union Vmxnet3_GenericDesc *gd;
+
+ rbi = rbi_base + ring->next2fill;
+ gd = ring->base + ring->next2fill;
+
+ if (rbi->buf_type == VMXNET3_RX_BUF_SKB) {
+ if (rbi->skb == NULL) {
+ rbi->skb = dev_alloc_skb(rbi->len +
+ NET_IP_ALIGN);
+ if (unlikely(rbi->skb == NULL)) {
+ rq->stats.rx_buf_alloc_failure++;
+ break;
+ }
+ rbi->skb->dev = adapter->netdev;
+
+ skb_reserve(rbi->skb, NET_IP_ALIGN);
+ rbi->dma_addr = pci_map_single(adapter->pdev,
+ rbi->skb->data, rbi->len,
+ PCI_DMA_FROMDEVICE);
+ } else {
+ /* rx buffer skipped by the device */
+ }
+ val = VMXNET3_RXD_BTYPE_HEAD << VMXNET3_RXD_BTYPE_SHIFT;
+ } else {
+ BUG_ON(rbi->buf_type != VMXNET3_RX_BUF_PAGE ||
+ rbi->len != PAGE_SIZE);
+
+ if (rbi->page == NULL) {
+ rbi->page = alloc_page(GFP_ATOMIC);
+ if (unlikely(rbi->page == NULL)) {
+ rq->stats.rx_buf_alloc_failure++;
+ break;
+ }
+ rbi->dma_addr = pci_map_page(adapter->pdev,
+ rbi->page, 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
+ } else {
+ /* rx buffers skipped by the device */
+ }
+ val = VMXNET3_RXD_BTYPE_BODY << VMXNET3_RXD_BTYPE_SHIFT;
+ }
+
+ BUG_ON(rbi->dma_addr == 0);
+ gd->rxd.addr = rbi->dma_addr;
+ gd->dword[2] = (ring->gen << VMXNET3_RXD_GEN_SHIFT) | val |
+ rbi->len;
+
+ num_allocated++;
+ vmxnet3_cmd_ring_adv_next2fill(ring);
+ }
+ rq->uncommitted[ring_idx] += num_allocated;
+
+ dprintk(KERN_ERR "alloc_rx_buf: %d allocated, next2fill %u, next2comp "
+ "%u, uncommited %u\n", num_allocated, ring->next2fill,
+ ring->next2comp, rq->uncommitted[ring_idx]);
+
+ /* so that the device can distinguish a full ring and an empty ring */
+ BUG_ON(num_allocated != 0 && ring->next2fill == ring->next2comp);
+
+ return num_allocated;
+}
+
+
+static void
+vmxnet3_append_frag(struct sk_buff *skb, struct Vmxnet3_RxCompDesc *rcd,
+ struct vmxnet3_rx_buf_info *rbi)
+{
+ struct skb_frag_struct *frag = skb_shinfo(skb)->frags +
+ skb_shinfo(skb)->nr_frags;
+
+ BUG_ON(skb_shinfo(skb)->nr_frags >= MAX_SKB_FRAGS);
+
+ frag->page = rbi->page;
+ frag->page_offset = 0;
+ frag->size = rcd->len;
+ skb->data_len += frag->size;
+ skb_shinfo(skb)->nr_frags++;
+}
+
+
+static void
+vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
+ struct vmxnet3_tx_queue *tq, struct pci_dev *pdev,
+ struct vmxnet3_adapter *adapter)
+{
+ u32 dw2, len;
+ unsigned long buf_offset;
+ int i;
+ union Vmxnet3_GenericDesc *gdesc;
+ struct vmxnet3_tx_buf_info *tbi = NULL;
+
+ BUG_ON(ctx->copy_size > skb_headlen(skb));
+
+ /* use the previous gen bit for the SOP desc */
+ dw2 = (tq->tx_ring.gen ^ 0x1) << VMXNET3_TXD_GEN_SHIFT;
+
+ ctx->sop_txd = tq->tx_ring.base + tq->tx_ring.next2fill;
+ gdesc = ctx->sop_txd; /* both loops below can be skipped */
+
+ /* no need to map the buffer if headers are copied */
+ if (ctx->copy_size) {
+ ctx->sop_txd->txd.addr = tq->data_ring.basePA +
+ tq->tx_ring.next2fill *
+ sizeof(struct Vmxnet3_TxDataDesc);
+ ctx->sop_txd->dword[2] = dw2 | ctx->copy_size;
+ ctx->sop_txd->dword[3] = 0;
+
+ 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",
+ 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);
+
+ /* use the right gen for non-SOP desc */
+ dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
+ }
+
+ /* linear part can use multiple tx desc if it's big */
+ len = skb_headlen(skb) - ctx->copy_size;
+ buf_offset = ctx->copy_size;
+ while (len) {
+ u32 buf_size;
+
+ buf_size = len > VMXNET3_MAX_TX_BUF_SIZE ?
+ VMXNET3_MAX_TX_BUF_SIZE : len;
+
+ tbi = tq->buf_info + tq->tx_ring.next2fill;
+ tbi->map_type = VMXNET3_MAP_SINGLE;
+ tbi->dma_addr = pci_map_single(adapter->pdev,
+ skb->data + buf_offset, buf_size,
+ PCI_DMA_TODEVICE);
+
+ tbi->len = buf_size; /* this automatically convert 2^14 to 0 */
+
+ gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
+ BUG_ON(gdesc->txd.gen == tq->tx_ring.gen);
+
+ gdesc->txd.addr = tbi->dma_addr;
+ gdesc->dword[2] = dw2 | buf_size;
+ gdesc->dword[3] = 0;
+
+ dprintk(KERN_ERR "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);
+ dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
+
+ len -= buf_size;
+ buf_offset += buf_size;
+ }
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
+
+ tbi = tq->buf_info + tq->tx_ring.next2fill;
+ tbi->map_type = VMXNET3_MAP_PAGE;
+ tbi->dma_addr = pci_map_page(adapter->pdev, frag->page,
+ frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
+
+ tbi->len = frag->size;
+
+ gdesc = tq->tx_ring.base + tq->tx_ring.next2fill;
+ BUG_ON(gdesc->txd.gen == tq->tx_ring.gen);
+
+ gdesc->txd.addr = tbi->dma_addr;
+ gdesc->dword[2] = dw2 | frag->size;
+ gdesc->dword[3] = 0;
+
+ dprintk(KERN_ERR "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);
+ dw2 = tq->tx_ring.gen << VMXNET3_TXD_GEN_SHIFT;
+ }
+
+ ctx->eop_txd = gdesc;
+
+ /* set the last buf_info for the pkt */
+ tbi->skb = skb;
+ tbi->sop_idx = ctx->sop_txd - tq->tx_ring.base;
+}
+
+
+/*
+ * parse and copy relevant protocol headers:
+ * For a tso pkt, relevant headers are L2/3/4 including options
+ * For a pkt requesting csum offloading, they are L2/3 and may include L4
+ * if it's a TCP/UDP pkt
+ *
+ * Returns:
+ * -1: error happens during parsing
+ * 0: protocol headers parsed, but too big to be copied
+ * 1: protocol headers parsed and copied
+ *
+ * Other effects:
+ * 1. related *ctx fields are updated.
+ * 2. ctx->copy_size is # of bytes copied
+ * 3. the portion copied is guaranteed to be in the linear part
+ *
+ */
+static int
+vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
+ struct vmxnet3_tx_ctx *ctx,
+ struct vmxnet3_adapter *adapter)
+{
+ struct Vmxnet3_TxDataDesc *tdd;
+
+ if (ctx->mss) {
+ ctx->eth_ip_hdr_size = skb_transport_offset(skb);
+ ctx->l4_hdr_size = ((struct tcphdr *)
+ skb_transport_header(skb))->doff * 4;
+ ctx->copy_size = ctx->eth_ip_hdr_size + ctx->l4_hdr_size;
+ } else {
+ unsigned int pull_size;
+
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ ctx->eth_ip_hdr_size = skb_transport_offset(skb);
+
+ if (ctx->ipv4) {
+ struct iphdr *iph = (struct iphdr *)
+ skb_network_header(skb);
+ if (iph->protocol == IPPROTO_TCP) {
+ pull_size = ctx->eth_ip_hdr_size +
+ sizeof(struct tcphdr);
+
+ if (unlikely(!pskb_may_pull(skb,
+ pull_size))) {
+ goto err;
+ }
+ ctx->l4_hdr_size = ((struct tcphdr *)
+ skb_transport_header(skb))->doff * 4;
+ } else if (iph->protocol == IPPROTO_UDP) {
+ ctx->l4_hdr_size =
+ sizeof(struct udphdr);
+ } else {
+ ctx->l4_hdr_size = 0;
+ }
+ } else {
+ /* for simplicity, don't copy L4 headers */
+ ctx->l4_hdr_size = 0;
+ }
+ ctx->copy_size = ctx->eth_ip_hdr_size +
+ ctx->l4_hdr_size;
+ } else {
+ ctx->eth_ip_hdr_size = 0;
+ ctx->l4_hdr_size = 0;
+ /* copy as much as allowed */
+ ctx->copy_size = min((unsigned int)VMXNET3_HDR_COPY_SIZE
+ , skb_headlen(skb));
+ }
+
+ /* make sure headers are accessible directly */
+ if (unlikely(!pskb_may_pull(skb, ctx->copy_size)))
+ goto err;
+ }
+
+ if (unlikely(ctx->copy_size > VMXNET3_HDR_COPY_SIZE)) {
+ tq->stats.oversized_hdr++;
+ ctx->copy_size = 0;
+ return 0;
+ }
+
+ 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",
+ ctx->copy_size, tq->tx_ring.next2fill);
+ return 1;
+
+err:
+ return -1;
+}
+
+
+static void
+vmxnet3_prepare_tso(struct sk_buff *skb,
+ struct vmxnet3_tx_ctx *ctx)
+{
+ struct tcphdr *tcph = (struct tcphdr *)skb_transport_header(skb);
+ if (ctx->ipv4) {
+ struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
+ iph->check = 0;
+ tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, 0,
+ IPPROTO_TCP, 0);
+ } else {
+ struct ipv6hdr *iph = (struct ipv6hdr *)skb_network_header(skb);
+ tcph->check = ~csum_ipv6_magic(&iph->saddr, &iph->daddr, 0,
+ IPPROTO_TCP, 0);
+ }
+}
+
+
+/*
+ * Transmits a pkt thru a given tq
+ * Returns:
+ * NETDEV_TX_OK: descriptors are setup successfully
+ * NETDEV_TX_OK: error occured, the pkt is dropped
+ * NETDEV_TX_BUSY: tx ring is full, queue is stopped
+ *
+ * Side-effects:
+ * 1. tx ring may be changed
+ * 2. tq stats may be updated accordingly
+ * 3. shared->txNumDeferred may be updated
+ */
+
+static int
+vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
+ struct vmxnet3_adapter *adapter, struct net_device *netdev)
+{
+ int ret;
+ u32 count;
+ unsigned long flags;
+ struct vmxnet3_tx_ctx ctx;
+ union Vmxnet3_GenericDesc *gdesc;
+
+ /* conservatively estimate # of descriptors to use */
+ count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) +
+ skb_shinfo(skb)->nr_frags + 1;
+
+ ctx.ipv4 = (skb->protocol == __constant_ntohs(ETH_P_IP));
+
+ ctx.mss = skb_shinfo(skb)->gso_size;
+ if (ctx.mss) {
+ if (skb_header_cloned(skb)) {
+ if (unlikely(pskb_expand_head(skb, 0, 0,
+ GFP_ATOMIC) != 0)) {
+ tq->stats.drop_tso++;
+ goto drop_pkt;
+ }
+ tq->stats.copy_skb_header++;
+ }
+ vmxnet3_prepare_tso(skb, &ctx);
+ } else {
+ if (unlikely(count > VMXNET3_MAX_TXD_PER_PKT)) {
+
+ /* non-tso pkts must not use more than
+ * VMXNET3_MAX_TXD_PER_PKT entries
+ */
+ if (skb_linearize(skb) != 0) {
+ tq->stats.drop_too_many_frags++;
+ goto drop_pkt;
+ }
+ tq->stats.linearized++;
+
+ /* recalculate the # of descriptors to use */
+ count = VMXNET3_TXD_NEEDED(skb_headlen(skb)) + 1;
+ }
+ }
+
+ ret = vmxnet3_parse_and_copy_hdr(skb, tq, &ctx, adapter);
+ if (ret >= 0) {
+ BUG_ON(ret <= 0 && ctx.copy_size != 0);
+ /* hdrs parsed, check against other limits */
+ if (ctx.mss) {
+ if (unlikely(ctx.eth_ip_hdr_size + ctx.l4_hdr_size >
+ VMXNET3_MAX_TX_BUF_SIZE)) {
+ goto hdr_too_big;
+ }
+ } else {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ if (unlikely(ctx.eth_ip_hdr_size +
+ skb->csum_offset >
+ VMXNET3_MAX_CSUM_OFFSET)) {
+ goto hdr_too_big;
+ }
+ }
+ }
+ } else {
+ tq->stats.drop_hdr_inspect_err++;
+ goto drop_pkt;
+ }
+
+ spin_lock_irqsave(&tq->tx_lock, flags);
+
+ 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"
+ " next2fill %u\n", adapter->netdev->name,
+ tq->tx_ring.next2comp, tq->tx_ring.next2fill);
+
+ vmxnet3_tq_stop(tq, adapter);
+ spin_unlock_irqrestore(&tq->tx_lock, flags);
+ return NETDEV_TX_BUSY;
+ }
+
+ /* fill tx descs related to addr & len */
+ vmxnet3_map_pkt(skb, &ctx, tq, adapter->pdev, adapter);
+
+ /* setup the EOP desc */
+ ctx.eop_txd->dword[3] = VMXNET3_TXD_CQ | VMXNET3_TXD_EOP;
+
+ /* setup the SOP desc */
+ gdesc = ctx.sop_txd;
+ if (ctx.mss) {
+ gdesc->txd.hlen = ctx.eth_ip_hdr_size + ctx.l4_hdr_size;
+ gdesc->txd.om = VMXNET3_OM_TSO;
+ gdesc->txd.msscof = ctx.mss;
+ tq->shared->txNumDeferred += (skb->len - gdesc->txd.hlen +
+ ctx.mss - 1) / ctx.mss;
+ } else {
+ if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ gdesc->txd.hlen = ctx.eth_ip_hdr_size;
+ gdesc->txd.om = VMXNET3_OM_CSUM;
+ gdesc->txd.msscof = ctx.eth_ip_hdr_size +
+ skb->csum_offset;
+ } else {
+ gdesc->txd.om = 0;
+ gdesc->txd.msscof = 0;
+ }
+ tq->shared->txNumDeferred++;
+ }
+
+ if (vlan_tx_tag_present(skb)) {
+ gdesc->txd.ti = 1;
+ gdesc->txd.tci = vlan_tx_tag_get(skb);
+ }
+
+ wmb();
+
+ /* 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",
+ (u32)((union Vmxnet3_GenericDesc *)ctx.sop_txd -
+ tq->tx_ring.base), gdesc->txd.addr, gdesc->dword[2],
+ gdesc->dword[3]);
+
+ spin_unlock_irqrestore(&tq->tx_lock, flags);
+
+ if (tq->shared->txNumDeferred >= tq->shared->txThreshold) {
+ tq->shared->txNumDeferred = 0;
+ VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_TXPROD,
+ tq->tx_ring.next2fill);
+ }
+ netdev->trans_start = jiffies;
+
+ return NETDEV_TX_OK;
+
+hdr_too_big:
+ tq->stats.drop_oversized_hdr++;
+drop_pkt:
+ tq->stats.drop_total++;
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+}
+
+
+static netdev_tx_t
+vmxnet3_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ struct vmxnet3_tx_queue *tq = &adapter->tx_queue;
+
+ return vmxnet3_tq_xmit(skb, tq, adapter, netdev);
+}
+
+
+static void
+vmxnet3_rx_csum(struct vmxnet3_adapter *adapter,
+ struct sk_buff *skb,
+ union Vmxnet3_GenericDesc *gdesc)
+{
+ if (!gdesc->rcd.cnc && adapter->rxcsum) {
+ /* typical case: TCP/UDP over IP and both csums are correct */
+ if ((gdesc->dword[3] & VMXNET3_RCD_CSUM_OK) ==
+ VMXNET3_RCD_CSUM_OK) {
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ BUG_ON(!(gdesc->rcd.tcp || gdesc->rcd.udp));
+ BUG_ON(!(gdesc->rcd.v4 || gdesc->rcd.v6));
+ BUG_ON(gdesc->rcd.frg);
+ } else {
+ if (gdesc->rcd.csum) {
+ skb->csum = htons(gdesc->rcd.csum);
+ skb->ip_summed = CHECKSUM_PARTIAL;
+ } else {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+ }
+ } else {
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+}
+
+
+static void
+vmxnet3_rx_error(struct vmxnet3_rx_queue *rq, struct Vmxnet3_RxCompDesc *rcd,
+ struct vmxnet3_rx_ctx *ctx, struct vmxnet3_adapter *adapter)
+{
+ rq->stats.drop_err++;
+ if (!rcd->fcs)
+ rq->stats.drop_fcs++;
+
+ rq->stats.drop_total++;
+
+ /*
+ * We do not unmap and chain the rx buffer to the skb.
+ * We basically pretend this buffer is not used and will be recycled
+ * by vmxnet3_rq_alloc_rx_buf()
+ */
+
+ /*
+ * ctx->skb may be NULL if this is the first and the only one
+ * desc for the pkt
+ */
+ if (ctx->skb)
+ dev_kfree_skb_irq(ctx->skb);
+
+ ctx->skb = NULL;
+}
+
+
+static int
+vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
+ struct vmxnet3_adapter *adapter, int quota)
+{
+ static u32 rxprod_reg[2] = {VMXNET3_REG_RXPROD, VMXNET3_REG_RXPROD2};
+ u32 num_rxd = 0;
+ struct Vmxnet3_RxCompDesc *rcd;
+ struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
+
+ rcd = &rq->comp_ring.base[rq->comp_ring.next2proc].rcd;
+ while (rcd->gen == rq->comp_ring.gen) {
+ struct vmxnet3_rx_buf_info *rbi;
+ struct sk_buff *skb;
+ int num_to_alloc;
+ struct Vmxnet3_RxDesc *rxd;
+ u32 idx, ring_idx;
+
+ if (num_rxd >= quota) {
+ /* we may stop even before we see the EOP desc of
+ * the current pkt
+ */
+ break;
+ }
+ num_rxd++;
+
+ idx = rcd->rxdIdx;
+ ring_idx = rcd->rqID == rq->qid ? 0 : 1;
+
+ rxd = &rq->rx_ring[ring_idx].base[idx].rxd;
+ rbi = rq->buf_info[ring_idx] + idx;
+
+ BUG_ON(rxd->addr != rbi->dma_addr || rxd->len != rbi->len);
+
+ if (unlikely(rcd->eop && rcd->err)) {
+ vmxnet3_rx_error(rq, rcd, ctx, adapter);
+ goto rcd_done;
+ }
+
+ if (rcd->sop) { /* first buf of the pkt */
+ BUG_ON(rxd->btype != VMXNET3_RXD_BTYPE_HEAD ||
+ rcd->rqID != rq->qid);
+
+ BUG_ON(rbi->buf_type != VMXNET3_RX_BUF_SKB);
+ BUG_ON(ctx->skb != NULL || rbi->skb == NULL);
+
+ 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",
+ ring_idx, idx);
+ goto rcd_done;
+ }
+
+ ctx->skb = rbi->skb;
+ rbi->skb = NULL;
+
+ pci_unmap_single(adapter->pdev, rbi->dma_addr, rbi->len,
+ PCI_DMA_FROMDEVICE);
+
+ skb_put(ctx->skb, rcd->len);
+ } else {
+ BUG_ON(ctx->skb == NULL);
+ /* non SOP buffer must be type 1 in most cases */
+ if (rbi->buf_type == VMXNET3_RX_BUF_PAGE) {
+ BUG_ON(rxd->btype != VMXNET3_RXD_BTYPE_BODY);
+
+ if (rcd->len) {
+ pci_unmap_page(adapter->pdev,
+ rbi->dma_addr, rbi->len,
+ PCI_DMA_FROMDEVICE);
+
+ vmxnet3_append_frag(ctx->skb, rcd, rbi);
+ rbi->page = NULL;
+ }
+ } else {
+ /*
+ * The only time a non-SOP buffer is type 0 is
+ * when it's EOP and error flag is raised, which
+ * has already been handled.
+ */
+ BUG_ON(true);
+ }
+ }
+
+ skb = ctx->skb;
+ if (rcd->eop) {
+ skb->len += skb->data_len;
+ skb->truesize += skb->data_len;
+
+ vmxnet3_rx_csum(adapter, skb,
+ (union Vmxnet3_GenericDesc *)rcd);
+ skb->protocol = eth_type_trans(skb, adapter->netdev);
+
+ if (unlikely(adapter->vlan_grp && rcd->ts)) {
+ vlan_hwaccel_receive_skb(skb,
+ adapter->vlan_grp, rcd->tci);
+ } else {
+ netif_receive_skb(skb);
+ }
+
+ adapter->netdev->last_rx = jiffies;
+ ctx->skb = NULL;
+ }
+
+rcd_done:
+ /* device may skip some rx descs */
+ rq->rx_ring[ring_idx].next2comp = idx;
+ VMXNET3_INC_RING_IDX_ONLY(rq->rx_ring[ring_idx].next2comp,
+ rq->rx_ring[ring_idx].size);
+
+ /* refill rx buffers frequently to avoid starving the h/w */
+ num_to_alloc = vmxnet3_cmd_ring_desc_avail(rq->rx_ring +
+ ring_idx);
+ if (unlikely(num_to_alloc > VMXNET3_RX_ALLOC_THRESHOLD(rq,
+ ring_idx, adapter))) {
+ vmxnet3_rq_alloc_rx_buf(rq, ring_idx, num_to_alloc,
+ adapter);
+
+ /* if needed, update the register */
+ if (unlikely(rq->shared->updateRxProd)) {
+ VMXNET3_WRITE_BAR0_REG(adapter,
+ rxprod_reg[ring_idx] + rq->qid * 8,
+ rq->rx_ring[ring_idx].next2fill);
+ rq->uncommitted[ring_idx] = 0;
+ }
+ }
+
+ vmxnet3_comp_ring_adv_next2proc(&rq->comp_ring);
+ rcd = &rq->comp_ring.base[rq->comp_ring.next2proc].rcd;
+ }
+
+ return num_rxd;
+}
+
+
+static void
+vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq,
+ struct vmxnet3_adapter *adapter)
+{
+ u32 i, ring_idx;
+ struct Vmxnet3_RxDesc *rxd;
+
+ for (ring_idx = 0; ring_idx < 2; ring_idx++) {
+ for (i = 0; i < rq->rx_ring[ring_idx].size; i++) {
+ rxd = &rq->rx_ring[ring_idx].base[i].rxd;
+
+ if (rxd->btype == VMXNET3_RXD_BTYPE_HEAD &&
+ rq->buf_info[ring_idx][i].skb) {
+ pci_unmap_single(adapter->pdev, rxd->addr,
+ rxd->len, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(rq->buf_info[ring_idx][i].skb);
+ rq->buf_info[ring_idx][i].skb = NULL;
+ } else if (rxd->btype == VMXNET3_RXD_BTYPE_BODY &&
+ rq->buf_info[ring_idx][i].page) {
+ pci_unmap_page(adapter->pdev, rxd->addr,
+ rxd->len, PCI_DMA_FROMDEVICE);
+ put_page(rq->buf_info[ring_idx][i].page);
+ rq->buf_info[ring_idx][i].page = NULL;
+ }
+ }
+
+ rq->rx_ring[ring_idx].gen = VMXNET3_INIT_GEN;
+ rq->rx_ring[ring_idx].next2fill =
+ rq->rx_ring[ring_idx].next2comp = 0;
+ rq->uncommitted[ring_idx] = 0;
+ }
+
+ rq->comp_ring.gen = VMXNET3_INIT_GEN;
+ rq->comp_ring.next2proc = 0;
+}
+
+
+void vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq,
+ struct vmxnet3_adapter *adapter)
+{
+ int i;
+ int j;
+
+ /* all rx buffers must have already been freed */
+ for (i = 0; i < 2; i++) {
+ if (rq->buf_info[i]) {
+ for (j = 0; j < rq->rx_ring[i].size; j++)
+ BUG_ON(rq->buf_info[i][j].page != NULL);
+ }
+ }
+
+
+ kfree(rq->buf_info[0]);
+
+ for (i = 0; i < 2; i++) {
+ if (rq->rx_ring[i].base) {
+ pci_free_consistent(adapter->pdev, rq->rx_ring[i].size
+ * sizeof(struct Vmxnet3_RxDesc),
+ rq->rx_ring[i].base,
+ rq->rx_ring[i].basePA);
+ rq->rx_ring[i].base = NULL;
+ }
+ rq->buf_info[i] = NULL;
+ }
+
+ if (rq->comp_ring.base) {
+ pci_free_consistent(adapter->pdev, rq->comp_ring.size *
+ sizeof(struct Vmxnet3_RxCompDesc),
+ rq->comp_ring.base, rq->comp_ring.basePA);
+ rq->comp_ring.base = NULL;
+ }
+}
+
+
+static int
+vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
+ struct vmxnet3_adapter *adapter)
+{
+ int i;
+
+ /* initialize buf_info */
+ for (i = 0; i < rq->rx_ring[0].size; i++) {
+
+ /* 1st buf for a pkt is skbuff */
+ if (i % adapter->rx_buf_per_pkt == 0) {
+ rq->buf_info[0][i].buf_type = VMXNET3_RX_BUF_SKB;
+ rq->buf_info[0][i].len = adapter->skb_buf_size;
+ } else { /* subsequent bufs for a pkt is frag */
+ rq->buf_info[0][i].buf_type = VMXNET3_RX_BUF_PAGE;
+ rq->buf_info[0][i].len = PAGE_SIZE;
+ }
+ }
+ for (i = 0; i < rq->rx_ring[1].size; i++) {
+ rq->buf_info[1][i].buf_type = VMXNET3_RX_BUF_PAGE;
+ rq->buf_info[1][i].len = PAGE_SIZE;
+ }
+
+ /* reset internal state and allocate buffers for both rings */
+ for (i = 0; i < 2; i++) {
+ rq->rx_ring[i].next2fill = rq->rx_ring[i].next2comp = 0;
+ rq->uncommitted[i] = 0;
+
+ memset(rq->rx_ring[i].base, 0, rq->rx_ring[i].size *
+ sizeof(struct Vmxnet3_RxDesc));
+ rq->rx_ring[i].gen = VMXNET3_INIT_GEN;
+ }
+ if (vmxnet3_rq_alloc_rx_buf(rq, 0, rq->rx_ring[0].size - 1,
+ adapter) == 0) {
+ /* at least has 1 rx buffer for the 1st ring */
+ return -ENOMEM;
+ }
+ vmxnet3_rq_alloc_rx_buf(rq, 1, rq->rx_ring[1].size - 1, adapter);
+
+ /* reset the comp ring */
+ rq->comp_ring.next2proc = 0;
+ memset(rq->comp_ring.base, 0, rq->comp_ring.size *
+ sizeof(struct Vmxnet3_RxCompDesc));
+ rq->comp_ring.gen = VMXNET3_INIT_GEN;
+
+ /* reset rxctx */
+ rq->rx_ctx.skb = NULL;
+
+ /* stats are not reset */
+ return 0;
+}
+
+
+static int
+vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter)
+{
+ int i;
+ size_t sz;
+ struct vmxnet3_rx_buf_info *bi;
+
+ for (i = 0; i < 2; i++) {
+
+ sz = rq->rx_ring[i].size * sizeof(struct Vmxnet3_RxDesc);
+ rq->rx_ring[i].base = pci_alloc_consistent(adapter->pdev, sz,
+ &rq->rx_ring[i].basePA);
+ if (!rq->rx_ring[i].base) {
+ printk(KERN_ERR "%s: failed to allocate rx ring %d\n",
+ adapter->netdev->name, i);
+ goto err;
+ }
+ }
+
+ sz = rq->comp_ring.size * sizeof(struct Vmxnet3_RxCompDesc);
+ rq->comp_ring.base = pci_alloc_consistent(adapter->pdev, sz,
+ &rq->comp_ring.basePA);
+ if (!rq->comp_ring.base) {
+ printk(KERN_ERR "%s: failed to allocate rx comp ring\n",
+ adapter->netdev->name);
+ goto err;
+ }
+
+ sz = sizeof(struct vmxnet3_rx_buf_info) * (rq->rx_ring[0].size +
+ rq->rx_ring[1].size);
+ bi = kmalloc(sz, GFP_KERNEL);
+ if (!bi) {
+ printk(KERN_ERR "%s: failed to allocate rx bufinfo\n",
+ adapter->netdev->name);
+ goto err;
+ }
+ memset(bi, 0, sz);
+ rq->buf_info[0] = bi;
+ rq->buf_info[1] = bi + rq->rx_ring[0].size;
+
+ return 0;
+
+err:
+ vmxnet3_rq_destroy(rq, adapter);
+ return -ENOMEM;
+}
+
+
+static int
+vmxnet3_do_poll(struct vmxnet3_adapter *adapter, int budget)
+{
+ if (unlikely(adapter->shared->ecr))
+ vmxnet3_process_events(adapter);
+
+ vmxnet3_tq_tx_complete(&adapter->tx_queue, adapter);
+ return vmxnet3_rq_rx_complete(&adapter->rx_queue, adapter, budget);
+}
+
+
+static int
+vmxnet3_poll(struct napi_struct *napi, int budget)
+{
+ struct vmxnet3_adapter *adapter = container_of(napi,
+ struct vmxnet3_adapter, napi);
+ int rxd_done;
+
+ rxd_done = vmxnet3_do_poll(adapter, budget);
+
+ if (rxd_done < budget) {
+ napi_complete(napi);
+ vmxnet3_enable_intr(adapter, 0);
+ }
+ return rxd_done;
+}
+
+
+/* Interrupt handler for vmxnet3 */
+static irqreturn_t
+vmxnet3_intr(int irq, void *dev_id)
+{
+ struct net_device *dev = dev_id;
+ struct vmxnet3_adapter *adapter = netdev_priv(dev);
+
+ if (unlikely(adapter->intr.type == VMXNET3_IT_INTX)) {
+ u32 icr = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_ICR);
+ if (unlikely(icr == 0))
+ /* not ours */
+ return IRQ_NONE;
+ }
+
+
+ /* disable intr if needed */
+ if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
+ vmxnet3_disable_intr(adapter, 0);
+
+ napi_schedule(&adapter->napi);
+
+ return IRQ_HANDLED;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+
+
+/* netpoll callback. */
+static void
+vmxnet3_netpoll(struct net_device *netdev)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ int irq;
+
+#ifdef CONFIG_PCI_MSI
+ if (adapter->intr.type == VMXNET3_IT_MSIX)
+ irq = adapter->intr.msix_entries[0].vector;
+ else
+#endif
+ irq = adapter->pdev->irq;
+
+ disable_irq(irq);
+ vmxnet3_intr(irq, netdev);
+ enable_irq(irq);
+}
+#endif
+
+static int
+vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
+{
+ int err;
+
+#ifdef CONFIG_PCI_MSI
+ if (adapter->intr.type == VMXNET3_IT_MSIX) {
+ /* we only use 1 MSI-X vector */
+ err = request_irq(adapter->intr.msix_entries[0].vector,
+ vmxnet3_intr, 0, adapter->netdev->name,
+ adapter->netdev);
+ } else
+#endif
+ if (adapter->intr.type == VMXNET3_IT_MSI) {
+ err = request_irq(adapter->pdev->irq, vmxnet3_intr, 0,
+ adapter->netdev->name, adapter->netdev);
+ } else {
+ err = request_irq(adapter->pdev->irq, vmxnet3_intr,
+ IRQF_SHARED, adapter->netdev->name,
+ adapter->netdev);
+ }
+
+ if (err)
+ printk(KERN_ERR "Failed to request irq %s (intr type:%d), error"
+ ":%d\n", adapter->netdev->name, adapter->intr.type, err);
+
+
+ if (!err) {
+ int i;
+ /* init our intr settings */
+ for (i = 0; i < adapter->intr.num_intrs; i++)
+ adapter->intr.mod_levels[i] = UPT1_IML_ADAPTIVE;
+
+ /* next setup intr index for all intr sources */
+ adapter->tx_queue.comp_ring.intr_idx = 0;
+ adapter->rx_queue.comp_ring.intr_idx = 0;
+ adapter->intr.event_intr_idx = 0;
+
+ printk(KERN_INFO "%s: intr type %u, mode %u, %u vectors "
+ "allocated\n", adapter->netdev->name, adapter->intr.type,
+ adapter->intr.mask_mode, adapter->intr.num_intrs);
+ }
+
+ return err;
+}
+
+
+static void
+vmxnet3_free_irqs(struct vmxnet3_adapter *adapter)
+{
+ BUG_ON(adapter->intr.type == VMXNET3_IT_AUTO ||
+ adapter->intr.num_intrs <= 0);
+
+ switch (adapter->intr.type) {
+#ifdef CONFIG_PCI_MSI
+ case VMXNET3_IT_MSIX:
+ {
+ int i;
+
+ for (i = 0; i < adapter->intr.num_intrs; i++)
+ free_irq(adapter->intr.msix_entries[i].vector,
+ adapter->netdev);
+ break;
+ }
+#endif
+ case VMXNET3_IT_MSI:
+ free_irq(adapter->pdev->irq, adapter->netdev);
+ break;
+ case VMXNET3_IT_INTX:
+ free_irq(adapter->pdev->irq, adapter->netdev);
+ break;
+ default:
+ BUG_ON(true);
+ }
+}
+
+
+static void
+vmxnet3_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ struct Vmxnet3_DriverShared *shared = adapter->shared;
+ u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+
+ if (grp) {
+ /* add vlan rx stripping. */
+ if (adapter->netdev->features & NETIF_F_HW_VLAN_RX) {
+ int i;
+ struct Vmxnet3_DSDevRead *devRead = &shared->devRead;
+ adapter->vlan_grp = grp;
+
+ /* update FEATURES to device */
+ devRead->misc.uptFeatures |= UPT1_F_RXVLAN;
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_FEATURE);
+ /*
+ * Clear entire vfTable; then enable untagged pkts.
+ * Note: setting one entry in vfTable to non-zero turns
+ * on VLAN rx filtering.
+ */
+ for (i = 0; i < VMXNET3_VFT_SIZE; i++)
+ vfTable[i] = 0;
+
+ VMXNET3_SET_VFTABLE_ENTRY(vfTable, 0);
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+ } else {
+ printk(KERN_ERR "%s: vlan_rx_register when device has "
+ "no NETIF_F_HW_VLAN_RX\n", netdev->name);
+ }
+ } else {
+ /* remove vlan rx stripping. */
+ struct Vmxnet3_DSDevRead *devRead = &shared->devRead;
+ adapter->vlan_grp = NULL;
+
+ if (devRead->misc.uptFeatures & UPT1_F_RXVLAN) {
+ int i;
+
+ for (i = 0; i < VMXNET3_VFT_SIZE; i++) {
+ /* clear entire vfTable; this also disables
+ * VLAN rx filtering
+ */
+ vfTable[i] = 0;
+ }
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+
+ /* update FEATURES to device */
+ devRead->misc.uptFeatures &= ~UPT1_F_RXVLAN;
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_FEATURE);
+ }
+ }
+}
+
+
+static void
+vmxnet3_restore_vlan(struct vmxnet3_adapter *adapter)
+{
+ if (adapter->vlan_grp) {
+ u16 vid;
+ u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+ bool activeVlan = false;
+
+ for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+ if (vlan_group_get_device(adapter->vlan_grp, vid)) {
+ VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
+ activeVlan = true;
+ }
+ }
+ if (activeVlan) {
+ /* continue to allow untagged pkts */
+ VMXNET3_SET_VFTABLE_ENTRY(vfTable, 0);
+ }
+ }
+}
+
+
+static void
+vmxnet3_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+
+ VMXNET3_SET_VFTABLE_ENTRY(vfTable, vid);
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+}
+
+
+static void
+vmxnet3_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ u32 *vfTable = adapter->shared->devRead.rxFilterConf.vfTable;
+
+ VMXNET3_CLEAR_VFTABLE_ENTRY(vfTable, vid);
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_VLAN_FILTERS);
+}
+
+
+static u8 *
+vmxnet3_copy_mc(struct net_device *netdev)
+{
+ u8 *buf = NULL;
+ u32 sz = netdev->mc_count * ETH_ALEN;
+
+ /* struct Vmxnet3_RxFilterConf.mfTableLen is u16. */
+ if (sz <= 0xffff) {
+ /* We may be called with BH disabled */
+ buf = kmalloc(sz, GFP_ATOMIC);
+ if (buf) {
+ int i;
+ struct dev_mc_list *mc = netdev->mc_list;
+
+ for (i = 0; i < netdev->mc_count; i++) {
+ BUG_ON(!mc);
+ memcpy(buf + i * ETH_ALEN, mc->dmi_addr,
+ ETH_ALEN);
+ mc = mc->next;
+ }
+ }
+ }
+ return buf;
+}
+
+
+static void
+vmxnet3_set_mc(struct net_device *netdev)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ struct Vmxnet3_RxFilterConf *rxConf =
+ &adapter->shared->devRead.rxFilterConf;
+ u8 *new_table = NULL;
+ u32 new_mode = VMXNET3_RXM_UCAST;
+
+ if (netdev->flags & IFF_PROMISC)
+ new_mode |= VMXNET3_RXM_PROMISC;
+
+ if (netdev->flags & IFF_BROADCAST)
+ new_mode |= VMXNET3_RXM_BCAST;
+
+ if (netdev->flags & IFF_ALLMULTI)
+ new_mode |= VMXNET3_RXM_ALL_MULTI;
+ else
+ if (netdev->mc_count > 0) {
+ new_table = vmxnet3_copy_mc(netdev);
+ if (new_table) {
+ new_mode |= VMXNET3_RXM_MCAST;
+ rxConf->mfTableLen = netdev->mc_count *
+ ETH_ALEN;
+ rxConf->mfTablePA = virt_to_phys(new_table);
+ } else {
+ printk(KERN_INFO "%s: failed to copy mcast list"
+ ", setting ALL_MULTI\n", netdev->name);
+ new_mode |= VMXNET3_RXM_ALL_MULTI;
+ }
+ }
+
+
+ if (!(new_mode & VMXNET3_RXM_MCAST)) {
+ rxConf->mfTableLen = 0;
+ rxConf->mfTablePA = 0;
+ }
+
+ if (new_mode != rxConf->rxMode) {
+ rxConf->rxMode = new_mode;
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_RX_MODE);
+ }
+
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_MAC_FILTERS);
+
+ kfree(new_table);
+}
+
+
+/*
+ * Set up driver_shared based on settings in adapter.
+ */
+
+static void
+vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
+{
+ struct Vmxnet3_DriverShared *shared = adapter->shared;
+ struct Vmxnet3_DSDevRead *devRead = &shared->devRead;
+ struct Vmxnet3_TxQueueConf *tqc;
+ struct Vmxnet3_RxQueueConf *rqc;
+ int i;
+
+ memset(shared, 0, sizeof(*shared));
+
+ /* driver settings */
+ shared->magic = VMXNET3_REV1_MAGIC;
+ devRead->misc.driverInfo.version = VMXNET3_DRIVER_VERSION_NUM;
+ devRead->misc.driverInfo.gos.gosBits = (sizeof(void *) == 4 ?
+ VMXNET3_GOS_BITS_32 : VMXNET3_GOS_BITS_64);
+ devRead->misc.driverInfo.gos.gosType = VMXNET3_GOS_TYPE_LINUX;
+ devRead->misc.driverInfo.vmxnet3RevSpt = 1;
+ devRead->misc.driverInfo.uptVerSpt = 1;
+
+ devRead->misc.ddPA = virt_to_phys(adapter);
+ devRead->misc.ddLen = sizeof(struct vmxnet3_adapter);
+
+ /* set up feature flags */
+ if (adapter->rxcsum)
+ devRead->misc.uptFeatures |= UPT1_F_RXCSUM;
+
+ if (adapter->lro) {
+ devRead->misc.uptFeatures |= UPT1_F_LRO;
+ devRead->misc.maxNumRxSG = 1 + MAX_SKB_FRAGS;
+ }
+ if ((adapter->netdev->features & NETIF_F_HW_VLAN_RX)
+ && adapter->vlan_grp) {
+ devRead->misc.uptFeatures |= UPT1_F_RXVLAN;
+ }
+
+ devRead->misc.mtu = adapter->netdev->mtu;
+ devRead->misc.queueDescPA = adapter->queue_desc_pa;
+ devRead->misc.queueDescLen = sizeof(struct Vmxnet3_TxQueueDesc) +
+ sizeof(struct Vmxnet3_RxQueueDesc);
+
+ /* tx queue settings */
+ BUG_ON(adapter->tx_queue.tx_ring.base == NULL);
+
+ devRead->misc.numTxQueues = 1;
+ tqc = &adapter->tqd_start->conf;
+ tqc->txRingBasePA = adapter->tx_queue.tx_ring.basePA;
+ tqc->dataRingBasePA = adapter->tx_queue.data_ring.basePA;
+ tqc->compRingBasePA = adapter->tx_queue.comp_ring.basePA;
+ tqc->ddPA = virt_to_phys(adapter->tx_queue.buf_info);
+ tqc->txRingSize = adapter->tx_queue.tx_ring.size;
+ tqc->dataRingSize = adapter->tx_queue.data_ring.size;
+ tqc->compRingSize = adapter->tx_queue.comp_ring.size;
+ tqc->ddLen = sizeof(struct vmxnet3_tx_buf_info) *
+ tqc->txRingSize;
+ tqc->intrIdx = adapter->tx_queue.comp_ring.intr_idx;
+
+ /* rx queue settings */
+ devRead->misc.numRxQueues = 1;
+ rqc = &adapter->rqd_start->conf;
+ rqc->rxRingBasePA[0] = adapter->rx_queue.rx_ring[0].basePA;
+ rqc->rxRingBasePA[1] = adapter->rx_queue.rx_ring[1].basePA;
+ rqc->compRingBasePA = adapter->rx_queue.comp_ring.basePA;
+ rqc->ddPA = virt_to_phys(adapter->rx_queue.buf_info);
+ rqc->rxRingSize[0] = adapter->rx_queue.rx_ring[0].size;
+ rqc->rxRingSize[1] = adapter->rx_queue.rx_ring[1].size;
+ rqc->compRingSize = adapter->rx_queue.comp_ring.size;
+ rqc->ddLen = sizeof(struct vmxnet3_rx_buf_info) *
+ (rqc->rxRingSize[0] + rqc->rxRingSize[1]);
+ rqc->intrIdx = adapter->rx_queue.comp_ring.intr_idx;
+
+ /* intr settings */
+ devRead->intrConf.autoMask = adapter->intr.mask_mode ==
+ VMXNET3_IMM_AUTO;
+ devRead->intrConf.numIntrs = adapter->intr.num_intrs;
+ for (i = 0; i < adapter->intr.num_intrs; i++)
+ devRead->intrConf.modLevels[i] = adapter->intr.mod_levels[i];
+
+ devRead->intrConf.eventIntrIdx = adapter->intr.event_intr_idx;
+
+ /* rx filter settings */
+ devRead->rxFilterConf.rxMode = 0;
+ vmxnet3_restore_vlan(adapter);
+ /* the rest are already zeroed */
+}
+
+
+int
+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"
+ " %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,
+ adapter->rx_queue.rx_ring[1].size);
+
+ vmxnet3_tq_init(&adapter->tx_queue, adapter);
+ err = vmxnet3_rq_init(&adapter->rx_queue, adapter);
+ if (err) {
+ printk(KERN_ERR "Failed to init rx queue for %s: error %d\n",
+ adapter->netdev->name, err);
+ goto rq_err;
+ }
+
+ err = vmxnet3_request_irqs(adapter);
+ if (err) {
+ printk(KERN_ERR "Failed to setup irq for %s: error %d\n",
+ adapter->netdev->name, err);
+ goto irq_err;
+ }
+
+ vmxnet3_setup_driver_shared(adapter);
+
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DSAL,
+ VMXNET3_GET_ADDR_LO(adapter->shared_pa));
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DSAH,
+ VMXNET3_GET_ADDR_HI(adapter->shared_pa));
+
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_ACTIVATE_DEV);
+ ret = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to activate dev %s: error %u\n",
+ adapter->netdev->name, ret);
+ err = -EINVAL;
+ goto activate_err;
+ }
+ VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_RXPROD,
+ adapter->rx_queue.rx_ring[0].next2fill);
+ VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_RXPROD2,
+ adapter->rx_queue.rx_ring[1].next2fill);
+
+ /* Apply the rx filter settins last. */
+ vmxnet3_set_mc(adapter->netdev);
+
+ /*
+ * Check link state when first activating device. It will start the
+ * tx queue if the link is up.
+ */
+ vmxnet3_check_link(adapter);
+
+ napi_enable(&adapter->napi);
+ vmxnet3_enable_all_intrs(adapter);
+ clear_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
+ return 0;
+
+activate_err:
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DSAL, 0);
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_DSAH, 0);
+ vmxnet3_free_irqs(adapter);
+irq_err:
+rq_err:
+ /* free up buffers we allocated */
+ vmxnet3_rq_cleanup(&adapter->rx_queue, adapter);
+ return err;
+}
+
+
+void
+vmxnet3_reset_dev(struct vmxnet3_adapter *adapter)
+{
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_RESET_DEV);
+}
+
+
+int
+vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter)
+{
+ if (test_and_set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state))
+ return 0;
+
+
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_QUIESCE_DEV);
+ vmxnet3_disable_all_intrs(adapter);
+
+ napi_disable(&adapter->napi);
+ netif_tx_disable(adapter->netdev);
+ adapter->link_speed = 0;
+ netif_carrier_off(adapter->netdev);
+
+ vmxnet3_tq_cleanup(&adapter->tx_queue, adapter);
+ vmxnet3_rq_cleanup(&adapter->rx_queue, adapter);
+ vmxnet3_free_irqs(adapter);
+ return 0;
+}
+
+
+static void
+vmxnet3_write_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac)
+{
+ u32 tmp;
+
+ tmp = *(u32 *)mac;
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_MACL, tmp);
+
+ tmp = (mac[5] << 8) | mac[4];
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_MACH, tmp);
+}
+
+
+static int
+vmxnet3_set_mac_addr(struct net_device *netdev, void *p)
+{
+ struct sockaddr *addr = p;
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ vmxnet3_write_mac_addr(adapter, addr->sa_data);
+
+ return 0;
+}
+
+
+/* ==================== initialization and cleanup routines ============ */
+
+static int
+vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, bool *dma64)
+{
+ int err;
+ unsigned long mmio_start, mmio_len;
+ struct pci_dev *pdev = adapter->pdev;
+
+ err = pci_enable_device(pdev);
+ if (err) {
+ printk(KERN_ERR "Failed to enable adapter %s: error %d\n",
+ pci_name(pdev), err);
+ return err;
+ }
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) {
+ if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) {
+ printk(KERN_ERR "pci_set_consistent_dma_mask failed "
+ "for adapter %s\n", pci_name(pdev));
+ err = -EIO;
+ goto err_set_mask;
+ }
+ *dma64 = true;
+ } else {
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
+ printk(KERN_ERR "pci_set_dma_mask failed for adapter "
+ "%s\n", pci_name(pdev));
+ err = -EIO;
+ goto err_set_mask;
+ }
+ *dma64 = false;
+ }
+
+ err = pci_request_selected_regions(pdev, (1 << 2) - 1,
+ vmxnet3_driver_name);
+ if (err) {
+ printk(KERN_ERR "Failed to request region for adapter %s: "
+ "error %d\n", pci_name(pdev), err);
+ goto err_set_mask;
+ }
+
+ pci_set_master(pdev);
+
+ mmio_start = pci_resource_start(pdev, 0);
+ mmio_len = pci_resource_len(pdev, 0);
+ adapter->hw_addr0 = ioremap(mmio_start, mmio_len);
+ if (!adapter->hw_addr0) {
+ printk(KERN_ERR "Failed to map bar0 for adapter %s\n",
+ pci_name(pdev));
+ err = -EIO;
+ goto err_ioremap;
+ }
+
+ mmio_start = pci_resource_start(pdev, 1);
+ mmio_len = pci_resource_len(pdev, 1);
+ adapter->hw_addr1 = ioremap(mmio_start, mmio_len);
+ if (!adapter->hw_addr1) {
+ printk(KERN_ERR "Failed to map bar1 for adapter %s\n",
+ pci_name(pdev));
+ err = -EIO;
+ goto err_bar1;
+ }
+ return 0;
+
+err_bar1:
+ iounmap(adapter->hw_addr0);
+err_ioremap:
+ pci_release_selected_regions(pdev, (1 << 2) - 1);
+err_set_mask:
+ pci_disable_device(pdev);
+ return err;
+}
+
+
+static void
+vmxnet3_free_pci_resources(struct vmxnet3_adapter *adapter)
+{
+ BUG_ON(!adapter->pdev);
+
+ iounmap(adapter->hw_addr0);
+ iounmap(adapter->hw_addr1);
+ pci_release_selected_regions(adapter->pdev, (1 << 2) - 1);
+ pci_disable_device(adapter->pdev);
+}
+
+
+static void
+vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
+{
+ size_t sz;
+
+ if (adapter->netdev->mtu <= VMXNET3_MAX_SKB_BUF_SIZE -
+ VMXNET3_MAX_ETH_HDR_SIZE) {
+ adapter->skb_buf_size = adapter->netdev->mtu +
+ VMXNET3_MAX_ETH_HDR_SIZE;
+ if (adapter->skb_buf_size < VMXNET3_MIN_T0_BUF_SIZE)
+ adapter->skb_buf_size = VMXNET3_MIN_T0_BUF_SIZE;
+
+ adapter->rx_buf_per_pkt = 1;
+ } else {
+ adapter->skb_buf_size = VMXNET3_MAX_SKB_BUF_SIZE;
+ sz = adapter->netdev->mtu - VMXNET3_MAX_SKB_BUF_SIZE +
+ VMXNET3_MAX_ETH_HDR_SIZE;
+ adapter->rx_buf_per_pkt = 1 + (sz + PAGE_SIZE - 1) / PAGE_SIZE;
+ }
+
+ /*
+ * for simplicity, force the ring0 size to be a multiple of
+ * rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN
+ */
+ sz = adapter->rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN;
+ adapter->rx_queue.rx_ring[0].size = (adapter->rx_queue.rx_ring[0].size +
+ sz - 1) / sz * sz;
+ adapter->rx_queue.rx_ring[0].size = min_t(u32,
+ adapter->rx_queue.rx_ring[0].size,
+ VMXNET3_RX_RING_MAX_SIZE / sz * sz);
+}
+
+
+int
+vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size,
+ u32 rx_ring_size, u32 rx_ring2_size)
+{
+ int err;
+
+ adapter->tx_queue.tx_ring.size = tx_ring_size;
+ adapter->tx_queue.data_ring.size = tx_ring_size;
+ adapter->tx_queue.comp_ring.size = tx_ring_size;
+ adapter->tx_queue.shared = &adapter->tqd_start->ctrl;
+ adapter->tx_queue.stopped = true;
+ err = vmxnet3_tq_create(&adapter->tx_queue, adapter);
+ if (err)
+ return err;
+
+ adapter->rx_queue.rx_ring[0].size = rx_ring_size;
+ adapter->rx_queue.rx_ring[1].size = rx_ring2_size;
+ vmxnet3_adjust_rx_ring_size(adapter);
+ adapter->rx_queue.comp_ring.size = adapter->rx_queue.rx_ring[0].size +
+ adapter->rx_queue.rx_ring[1].size;
+ adapter->rx_queue.qid = 0;
+ adapter->rx_queue.qid2 = 1;
+ adapter->rx_queue.shared = &adapter->rqd_start->ctrl;
+ err = vmxnet3_rq_create(&adapter->rx_queue, adapter);
+ if (err)
+ vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
+
+ return err;
+}
+
+static int
+vmxnet3_open(struct net_device *netdev)
+{
+ struct vmxnet3_adapter *adapter;
+ int err;
+
+ adapter = netdev_priv(netdev);
+
+ spin_lock_init(&adapter->tx_queue.tx_lock);
+
+ err = vmxnet3_create_queues(adapter, VMXNET3_DEF_TX_RING_SIZE,
+ VMXNET3_DEF_RX_RING_SIZE,
+ VMXNET3_DEF_RX_RING_SIZE);
+ if (err)
+ goto queue_err;
+
+ err = vmxnet3_activate_dev(adapter);
+ if (err)
+ goto activate_err;
+
+ return 0;
+
+activate_err:
+ vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
+ vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
+queue_err:
+ return err;
+}
+
+
+static int
+vmxnet3_close(struct net_device *netdev)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+
+ /*
+ * Reset_work may be in the middle of resetting the device, wait for its
+ * completion.
+ */
+ while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state))
+ msleep(1);
+
+ vmxnet3_quiesce_dev(adapter);
+
+ vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
+ vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
+
+ clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
+
+
+ return 0;
+}
+
+
+void
+vmxnet3_force_close(struct vmxnet3_adapter *adapter)
+{
+ /*
+ * we must clear VMXNET3_STATE_BIT_RESETTING, otherwise
+ * vmxnet3_close() will deadlock.
+ */
+ BUG_ON(test_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state));
+
+ /* we need to enable NAPI, otherwise dev_close will deadlock */
+ napi_enable(&adapter->napi);
+ dev_close(adapter->netdev);
+}
+
+
+static int
+vmxnet3_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ int err = 0;
+
+ if (new_mtu < VMXNET3_MIN_MTU || new_mtu > VMXNET3_MAX_MTU)
+ return -EINVAL;
+
+ if (new_mtu > 1500 && !adapter->jumbo_frame)
+ return -EINVAL;
+
+ netdev->mtu = new_mtu;
+
+ /*
+ * Reset_work may be in the middle of resetting the device, wait for its
+ * completion.
+ */
+ while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state))
+ msleep(1);
+
+ if (netif_running(netdev)) {
+ vmxnet3_quiesce_dev(adapter);
+ vmxnet3_reset_dev(adapter);
+
+ /* we need to re-create the rx queue based on the new mtu */
+ vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
+ vmxnet3_adjust_rx_ring_size(adapter);
+ adapter->rx_queue.comp_ring.size =
+ adapter->rx_queue.rx_ring[0].size +
+ adapter->rx_queue.rx_ring[1].size;
+ err = vmxnet3_rq_create(&adapter->rx_queue, adapter);
+ if (err) {
+ printk(KERN_ERR "%s: failed to re-create rx queue,"
+ " error %d. Closing it.\n", netdev->name, err);
+ goto out;
+ }
+
+ err = vmxnet3_activate_dev(adapter);
+ if (err) {
+ printk(KERN_ERR "%s: failed to re-activate, error %d. "
+ "Closing it\n", netdev->name, err);
+ goto out;
+ }
+ }
+
+out:
+ clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
+ if (err)
+ vmxnet3_force_close(adapter);
+
+ return err;
+}
+
+
+static void
+vmxnet3_declare_features(struct vmxnet3_adapter *adapter, bool dma64)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ netdev->features = NETIF_F_SG |
+ NETIF_F_HW_CSUM |
+ NETIF_F_HW_VLAN_TX |
+ NETIF_F_HW_VLAN_RX |
+ NETIF_F_HW_VLAN_FILTER |
+ NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_LRO;
+
+ printk(KERN_INFO "features: sg csum vlan jf tso tsoIPv6 lro");
+
+ adapter->rxcsum = true;
+ adapter->jumbo_frame = true;
+ adapter->lro = true;
+
+ if (dma64) {
+ netdev->features |= NETIF_F_HIGHDMA;
+ printk(" highDMA");
+ }
+
+ netdev->vlan_features = netdev->features;
+ printk("\n");
+}
+
+
+static void
+vmxnet3_read_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac)
+{
+ u32 tmp;
+
+ tmp = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_MACL);
+ *(u32 *)mac = tmp;
+
+ tmp = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_MACH);
+ mac[4] = tmp & 0xff;
+ mac[5] = (tmp >> 8) & 0xff;
+}
+
+
+static void
+vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
+{
+ u32 cfg;
+
+ /* intr settings */
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_GET_CONF_INTR);
+ cfg = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
+ adapter->intr.type = cfg & 0x3;
+ adapter->intr.mask_mode = (cfg >> 2) & 0x3;
+
+ if (adapter->intr.type == VMXNET3_IT_AUTO) {
+ int err;
+
+#ifdef CONFIG_PCI_MSI
+ adapter->intr.msix_entries[0].entry = 0;
+ err = pci_enable_msix(adapter->pdev, adapter->intr.msix_entries,
+ VMXNET3_LINUX_MAX_MSIX_VECT);
+ if (!err) {
+ adapter->intr.num_intrs = 1;
+ adapter->intr.type = VMXNET3_IT_MSIX;
+ return;
+ }
+#endif
+
+ err = pci_enable_msi(adapter->pdev);
+ if (!err) {
+ adapter->intr.num_intrs = 1;
+ adapter->intr.type = VMXNET3_IT_MSI;
+ return;
+ }
+ }
+
+ adapter->intr.type = VMXNET3_IT_INTX;
+
+ /* INT-X related setting */
+ adapter->intr.num_intrs = 1;
+}
+
+
+static void
+vmxnet3_free_intr_resources(struct vmxnet3_adapter *adapter)
+{
+ if (adapter->intr.type == VMXNET3_IT_MSIX)
+ pci_disable_msix(adapter->pdev);
+ else if (adapter->intr.type == VMXNET3_IT_MSI)
+ pci_disable_msi(adapter->pdev);
+ else
+ BUG_ON(adapter->intr.type != VMXNET3_IT_INTX);
+}
+
+
+static void
+vmxnet3_tx_timeout(struct net_device *netdev)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ adapter->tx_timeout_count++;
+
+ printk(KERN_ERR "%s: tx hang\n", adapter->netdev->name);
+ schedule_work(&adapter->work);
+}
+
+
+static void
+vmxnet3_reset_work(struct work_struct *data)
+{
+ struct vmxnet3_adapter *adapter;
+
+ adapter = container_of(data, struct vmxnet3_adapter, work);
+
+ /* if another thread is resetting the device, no need to proceed */
+ if (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state))
+ return;
+
+ /* if the device is closed, we must leave it alone */
+ if (netif_running(adapter->netdev)) {
+ printk(KERN_INFO "%s: resetting\n", adapter->netdev->name);
+ vmxnet3_quiesce_dev(adapter);
+ vmxnet3_reset_dev(adapter);
+ vmxnet3_activate_dev(adapter);
+ } else {
+ printk(KERN_INFO "%s: already closed\n", adapter->netdev->name);
+ }
+
+ clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
+}
+
+
+static int __devinit
+vmxnet3_probe_device(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ static const struct net_device_ops vmxnet3_netdev_ops = {
+ .ndo_open = vmxnet3_open,
+ .ndo_stop = vmxnet3_close,
+ .ndo_start_xmit = vmxnet3_xmit_frame,
+ .ndo_set_mac_address = vmxnet3_set_mac_addr,
+ .ndo_change_mtu = vmxnet3_change_mtu,
+ .ndo_get_stats = vmxnet3_get_stats,
+ .ndo_tx_timeout = vmxnet3_tx_timeout,
+ .ndo_set_multicast_list = vmxnet3_set_mc,
+ .ndo_vlan_rx_register = vmxnet3_vlan_rx_register,
+ .ndo_vlan_rx_add_vid = vmxnet3_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = vmxnet3_vlan_rx_kill_vid,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = vmxnet3_netpoll,
+#endif
+ };
+ int err;
+ bool dma64 = false; /* stupid gcc */
+ u32 ver;
+ struct net_device *netdev;
+ struct vmxnet3_adapter *adapter;
+ u8 mac[ETH_ALEN];
+
+ netdev = alloc_etherdev(sizeof(struct vmxnet3_adapter));
+ if (!netdev) {
+ printk(KERN_ERR "Failed to alloc ethernet device for adapter "
+ "%s\n", pci_name(pdev));
+ return -ENOMEM;
+ }
+
+ pci_set_drvdata(pdev, netdev);
+ adapter = netdev_priv(netdev);
+ adapter->netdev = netdev;
+ adapter->pdev = pdev;
+
+ adapter->shared = pci_alloc_consistent(adapter->pdev,
+ sizeof(struct Vmxnet3_DriverShared),
+ &adapter->shared_pa);
+ if (!adapter->shared) {
+ printk(KERN_ERR "Failed to allocate memory for %s\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto err_alloc_shared;
+ }
+
+ adapter->tqd_start = pci_alloc_consistent(adapter->pdev,
+ sizeof(struct Vmxnet3_TxQueueDesc) +
+ sizeof(struct Vmxnet3_RxQueueDesc),
+ &adapter->queue_desc_pa);
+
+ if (!adapter->tqd_start) {
+ printk(KERN_ERR "Failed to allocate memory for %s\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto err_alloc_queue_desc;
+ }
+ adapter->rqd_start = (struct Vmxnet3_RxQueueDesc *)(adapter->tqd_start
+ + 1);
+
+ adapter->pm_conf = kmalloc(sizeof(struct Vmxnet3_PMConf), GFP_KERNEL);
+ if (adapter->pm_conf == NULL) {
+ printk(KERN_ERR "Failed to allocate memory for %s\n",
+ pci_name(pdev));
+ err = -ENOMEM;
+ goto err_alloc_pm;
+ }
+
+ err = vmxnet3_alloc_pci_resources(adapter, &dma64);
+ if (err < 0)
+ goto err_alloc_pci;
+
+ ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS);
+ if (ver & 1) {
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1);
+ } else {
+ printk(KERN_ERR "Incompatible h/w version (0x%x) for adapter"
+ " %s\n", ver, pci_name(pdev));
+ err = -EBUSY;
+ goto err_ver;
+ }
+
+ ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_UVRS);
+ if (ver & 1) {
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_UVRS, 1);
+ } else {
+ printk(KERN_ERR "Incompatible upt version (0x%x) for "
+ "adapter %s\n", ver, pci_name(pdev));
+ err = -EBUSY;
+ goto err_ver;
+ }
+
+ vmxnet3_declare_features(adapter, dma64);
+
+ adapter->dev_number = atomic_read(&devices_found);
+ vmxnet3_alloc_intr_resources(adapter);
+
+ vmxnet3_read_mac_addr(adapter, mac);
+ memcpy(netdev->dev_addr, mac, netdev->addr_len);
+
+ netdev->netdev_ops = &vmxnet3_netdev_ops;
+ netdev->watchdog_timeo = 5 * HZ;
+ vmxnet3_set_ethtool_ops(netdev);
+
+ INIT_WORK(&adapter->work, vmxnet3_reset_work);
+
+ netif_napi_add(netdev, &adapter->napi, vmxnet3_poll, 64);
+ SET_NETDEV_DEV(netdev, &pdev->dev);
+ err = register_netdev(netdev);
+
+ if (err) {
+ printk(KERN_ERR "Failed to register adapter %s\n",
+ pci_name(pdev));
+ goto err_register;
+ }
+
+ set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
+ atomic_inc(&devices_found);
+ return 0;
+
+err_register:
+ vmxnet3_free_intr_resources(adapter);
+err_ver:
+ vmxnet3_free_pci_resources(adapter);
+err_alloc_pci:
+ kfree(adapter->pm_conf);
+err_alloc_pm:
+ pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_TxQueueDesc) +
+ sizeof(struct Vmxnet3_RxQueueDesc),
+ adapter->tqd_start, adapter->queue_desc_pa);
+err_alloc_queue_desc:
+ pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_DriverShared),
+ adapter->shared, adapter->shared_pa);
+err_alloc_shared:
+ pci_set_drvdata(pdev, NULL);
+ free_netdev(netdev);
+ return err;
+}
+
+
+static void __devexit
+vmxnet3_remove_device(struct pci_dev *pdev)
+{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+
+ flush_scheduled_work();
+
+ unregister_netdev(netdev);
+
+ vmxnet3_free_intr_resources(adapter);
+ vmxnet3_free_pci_resources(adapter);
+ kfree(adapter->pm_conf);
+ pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_TxQueueDesc) +
+ sizeof(struct Vmxnet3_RxQueueDesc),
+ adapter->tqd_start, adapter->queue_desc_pa);
+ pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_DriverShared),
+ adapter->shared, adapter->shared_pa);
+ free_netdev(netdev);
+}
+
+
+#ifdef CONFIG_PM
+
+static int
+vmxnet3_suspend(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ struct Vmxnet3_PMConf *pmConf;
+ struct ethhdr *ehdr;
+ struct arphdr *ahdr;
+ u8 *arpreq;
+ struct in_device *in_dev;
+ struct in_ifaddr *ifa;
+ int i = 0;
+
+ if (!netif_running(netdev))
+ return 0;
+
+ vmxnet3_disable_all_intrs(adapter);
+ vmxnet3_free_irqs(adapter);
+ vmxnet3_free_intr_resources(adapter);
+
+ netif_device_detach(netdev);
+ netif_stop_queue(netdev);
+
+ /* Create wake-up filters. */
+ pmConf = adapter->pm_conf;
+ memset(pmConf, 0, sizeof(*pmConf));
+
+ if (adapter->wol & WAKE_UCAST) {
+ pmConf->filters[i].patternSize = ETH_ALEN;
+ pmConf->filters[i].maskSize = 1;
+ memcpy(pmConf->filters[i].pattern, netdev->dev_addr, ETH_ALEN);
+ pmConf->filters[i].mask[0] = 0x3F; /* LSB ETH_ALEN bits */
+
+ pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER;
+ i++;
+ }
+
+ if (adapter->wol & WAKE_ARP) {
+ in_dev = in_dev_get(netdev);
+ if (!in_dev)
+ goto skip_arp;
+
+ ifa = (struct in_ifaddr *)in_dev->ifa_list;
+ if (!ifa)
+ goto skip_arp;
+
+ pmConf->filters[i].patternSize = ETH_HLEN + /* Ethernet header*/
+ sizeof(struct arphdr) + /* ARP header */
+ 2 * ETH_ALEN + /* 2 Ethernet addresses*/
+ 2 * sizeof(u32); /*2 IPv4 addresses */
+ pmConf->filters[i].maskSize =
+ (pmConf->filters[i].patternSize - 1) / 8 + 1;
+
+ /* ETH_P_ARP in Ethernet header. */
+ ehdr = (struct ethhdr *)pmConf->filters[i].pattern;
+ ehdr->h_proto = htons(ETH_P_ARP);
+
+ /* ARPOP_REQUEST in ARP header. */
+ ahdr = (struct arphdr *)&pmConf->filters[i].pattern[ETH_HLEN];
+ ahdr->ar_op = htons(ARPOP_REQUEST);
+ arpreq = (u8 *)(ahdr + 1);
+
+ /* The Unicast IPv4 address in 'tip' field. */
+ arpreq += 2 * ETH_ALEN + sizeof(u32);
+ *(u32 *)arpreq = ifa->ifa_address;
+
+ /* The mask for the relevant bits. */
+ pmConf->filters[i].mask[0] = 0x00;
+ pmConf->filters[i].mask[1] = 0x30; /* ETH_P_ARP */
+ pmConf->filters[i].mask[2] = 0x30; /* ARPOP_REQUEST */
+ pmConf->filters[i].mask[3] = 0x00;
+ pmConf->filters[i].mask[4] = 0xC0; /* IPv4 TIP */
+ pmConf->filters[i].mask[5] = 0x03; /* IPv4 TIP */
+ in_dev_put(in_dev);
+
+ pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_FILTER;
+ i++;
+ }
+
+skip_arp:
+ if (adapter->wol & WAKE_MAGIC)
+ pmConf->wakeUpEvents |= VMXNET3_PM_WAKEUP_MAGIC;
+
+ pmConf->numFilters = i;
+
+ adapter->shared->devRead.pmConfDesc.confVer = 1;
+ adapter->shared->devRead.pmConfDesc.confLen = sizeof(*pmConf);
+ adapter->shared->devRead.pmConfDesc.confPA = virt_to_phys(pmConf);
+
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_PMCFG);
+
+ pci_save_state(pdev);
+ pci_enable_wake(pdev, pci_choose_state(pdev, PMSG_SUSPEND),
+ adapter->wol);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, PMSG_SUSPEND));
+
+ return 0;
+}
+
+
+static int
+vmxnet3_resume(struct device *device)
+{
+ int err;
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ struct Vmxnet3_PMConf *pmConf;
+
+ if (!netif_running(netdev))
+ return 0;
+
+ /* Destroy wake-up filters. */
+ pmConf = adapter->pm_conf;
+ memset(pmConf, 0, sizeof(*pmConf));
+
+ adapter->shared->devRead.pmConfDesc.confVer = 1;
+ adapter->shared->devRead.pmConfDesc.confLen = sizeof(*pmConf);
+ adapter->shared->devRead.pmConfDesc.confPA = virt_to_phys(pmConf);
+
+ netif_device_attach(netdev);
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ err = pci_enable_device_mem(pdev);
+ if (err != 0)
+ return err;
+
+ pci_enable_wake(pdev, PCI_D0, 0);
+
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_PMCFG);
+ vmxnet3_alloc_intr_resources(adapter);
+ vmxnet3_request_irqs(adapter);
+ vmxnet3_enable_all_intrs(adapter);
+
+ return 0;
+}
+
+static struct dev_pm_ops vmxnet3_pm_ops = {
+ .suspend = vmxnet3_suspend,
+ .resume = vmxnet3_resume,
+};
+#endif
+
+static struct pci_driver vmxnet3_driver = {
+ .name = vmxnet3_driver_name,
+ .id_table = vmxnet3_pciid_table,
+ .probe = vmxnet3_probe_device,
+ .remove = __devexit_p(vmxnet3_remove_device),
+#ifdef CONFIG_PM
+ .driver.pm = &vmxnet3_pm_ops,
+#endif
+};
+
+
+static int __init
+vmxnet3_init_module(void)
+{
+ printk(KERN_INFO "%s - version %s\n", VMXNET3_DRIVER_DESC,
+ VMXNET3_DRIVER_VERSION_REPORT);
+ return pci_register_driver(&vmxnet3_driver);
+}
+
+module_init(vmxnet3_init_module);
+
+
+static void
+vmxnet3_exit_module(void)
+{
+ pci_unregister_driver(&vmxnet3_driver);
+}
+
+module_exit(vmxnet3_exit_module);
+
+MODULE_AUTHOR("VMware, Inc.");
+MODULE_DESCRIPTION(VMXNET3_DRIVER_DESC);
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(VMXNET3_DRIVER_VERSION_STRING);
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
new file mode 100644
index 000000000000..c2c15e4cafc7
--- /dev/null
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -0,0 +1,566 @@
+/*
+ * Linux driver for VMware's vmxnet3 ethernet NIC.
+ *
+ * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License and no 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Maintained by: Shreyas Bhatewara <pv-drivers@vmware.com>
+ *
+ */
+
+
+#include "vmxnet3_int.h"
+
+struct vmxnet3_stat_desc {
+ char desc[ETH_GSTRING_LEN];
+ int offset;
+};
+
+
+static u32
+vmxnet3_get_rx_csum(struct net_device *netdev)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ return adapter->rxcsum;
+}
+
+
+static int
+vmxnet3_set_rx_csum(struct net_device *netdev, u32 val)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+
+ if (adapter->rxcsum != val) {
+ adapter->rxcsum = val;
+ if (netif_running(netdev)) {
+ if (val)
+ adapter->shared->devRead.misc.uptFeatures |=
+ UPT1_F_RXCSUM;
+ else
+ adapter->shared->devRead.misc.uptFeatures &=
+ ~UPT1_F_RXCSUM;
+
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_FEATURE);
+ }
+ }
+ return 0;
+}
+
+
+/* per tq stats maintained by the device */
+static const struct vmxnet3_stat_desc
+vmxnet3_tq_dev_stats[] = {
+ /* description, offset */
+ { "TSO pkts tx", offsetof(struct UPT1_TxStats, TSOPktsTxOK) },
+ { "TSO bytes tx", offsetof(struct UPT1_TxStats, TSOBytesTxOK) },
+ { "ucast pkts tx", offsetof(struct UPT1_TxStats, ucastPktsTxOK) },
+ { "ucast bytes tx", offsetof(struct UPT1_TxStats, ucastBytesTxOK) },
+ { "mcast pkts tx", offsetof(struct UPT1_TxStats, mcastPktsTxOK) },
+ { "mcast bytes tx", offsetof(struct UPT1_TxStats, mcastBytesTxOK) },
+ { "bcast pkts tx", offsetof(struct UPT1_TxStats, bcastPktsTxOK) },
+ { "bcast bytes tx", offsetof(struct UPT1_TxStats, bcastBytesTxOK) },
+ { "pkts tx err", offsetof(struct UPT1_TxStats, pktsTxError) },
+ { "pkts tx discard", offsetof(struct UPT1_TxStats, pktsTxDiscard) },
+};
+
+/* per tq stats maintained by the driver */
+static const struct vmxnet3_stat_desc
+vmxnet3_tq_driver_stats[] = {
+ /* description, offset */
+ {"drv dropped tx total", offsetof(struct vmxnet3_tq_driver_stats,
+ drop_total) },
+ { " too many frags", offsetof(struct vmxnet3_tq_driver_stats,
+ drop_too_many_frags) },
+ { " giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
+ drop_oversized_hdr) },
+ { " hdr err", offsetof(struct vmxnet3_tq_driver_stats,
+ drop_hdr_inspect_err) },
+ { " tso", offsetof(struct vmxnet3_tq_driver_stats,
+ drop_tso) },
+ { "ring full", offsetof(struct vmxnet3_tq_driver_stats,
+ tx_ring_full) },
+ { "pkts linearized", offsetof(struct vmxnet3_tq_driver_stats,
+ linearized) },
+ { "hdr cloned", offsetof(struct vmxnet3_tq_driver_stats,
+ copy_skb_header) },
+ { "giant hdr", offsetof(struct vmxnet3_tq_driver_stats,
+ oversized_hdr) },
+};
+
+/* per rq stats maintained by the device */
+static const struct vmxnet3_stat_desc
+vmxnet3_rq_dev_stats[] = {
+ { "LRO pkts rx", offsetof(struct UPT1_RxStats, LROPktsRxOK) },
+ { "LRO byte rx", offsetof(struct UPT1_RxStats, LROBytesRxOK) },
+ { "ucast pkts rx", offsetof(struct UPT1_RxStats, ucastPktsRxOK) },
+ { "ucast bytes rx", offsetof(struct UPT1_RxStats, ucastBytesRxOK) },
+ { "mcast pkts rx", offsetof(struct UPT1_RxStats, mcastPktsRxOK) },
+ { "mcast bytes rx", offsetof(struct UPT1_RxStats, mcastBytesRxOK) },
+ { "bcast pkts rx", offsetof(struct UPT1_RxStats, bcastPktsRxOK) },
+ { "bcast bytes rx", offsetof(struct UPT1_RxStats, bcastBytesRxOK) },
+ { "pkts rx out of buf", offsetof(struct UPT1_RxStats, pktsRxOutOfBuf) },
+ { "pkts rx err", offsetof(struct UPT1_RxStats, pktsRxError) },
+};
+
+/* per rq stats maintained by the driver */
+static const struct vmxnet3_stat_desc
+vmxnet3_rq_driver_stats[] = {
+ /* description, offset */
+ { "drv dropped rx total", offsetof(struct vmxnet3_rq_driver_stats,
+ drop_total) },
+ { " err", offsetof(struct vmxnet3_rq_driver_stats,
+ drop_err) },
+ { " fcs", offsetof(struct vmxnet3_rq_driver_stats,
+ drop_fcs) },
+ { "rx buf alloc fail", offsetof(struct vmxnet3_rq_driver_stats,
+ rx_buf_alloc_failure) },
+};
+
+/* gloabl stats maintained by the driver */
+static const struct vmxnet3_stat_desc
+vmxnet3_global_stats[] = {
+ /* description, offset */
+ { "tx timeout count", offsetof(struct vmxnet3_adapter,
+ tx_timeout_count) }
+};
+
+
+struct net_device_stats *
+vmxnet3_get_stats(struct net_device *netdev)
+{
+ struct vmxnet3_adapter *adapter;
+ struct vmxnet3_tq_driver_stats *drvTxStats;
+ struct vmxnet3_rq_driver_stats *drvRxStats;
+ struct UPT1_TxStats *devTxStats;
+ struct UPT1_RxStats *devRxStats;
+ struct net_device_stats *net_stats = &netdev->stats;
+
+ adapter = netdev_priv(netdev);
+
+ /* Collect the dev stats into the shared area */
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
+
+ /* Assuming that we have a single queue device */
+ devTxStats = &adapter->tqd_start->stats;
+ devRxStats = &adapter->rqd_start->stats;
+
+ /* Get access to the driver stats per queue */
+ drvTxStats = &adapter->tx_queue.stats;
+ drvRxStats = &adapter->rx_queue.stats;
+
+ memset(net_stats, 0, sizeof(*net_stats));
+
+ net_stats->rx_packets = devRxStats->ucastPktsRxOK +
+ devRxStats->mcastPktsRxOK +
+ devRxStats->bcastPktsRxOK;
+
+ net_stats->tx_packets = devTxStats->ucastPktsTxOK +
+ devTxStats->mcastPktsTxOK +
+ devTxStats->bcastPktsTxOK;
+
+ net_stats->rx_bytes = devRxStats->ucastBytesRxOK +
+ devRxStats->mcastBytesRxOK +
+ devRxStats->bcastBytesRxOK;
+
+ net_stats->tx_bytes = devTxStats->ucastBytesTxOK +
+ devTxStats->mcastBytesTxOK +
+ devTxStats->bcastBytesTxOK;
+
+ net_stats->rx_errors = devRxStats->pktsRxError;
+ net_stats->tx_errors = devTxStats->pktsTxError;
+ net_stats->rx_dropped = drvRxStats->drop_total;
+ net_stats->tx_dropped = drvTxStats->drop_total;
+ net_stats->multicast = devRxStats->mcastPktsRxOK;
+
+ return net_stats;
+}
+
+static int
+vmxnet3_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ARRAY_SIZE(vmxnet3_tq_dev_stats) +
+ ARRAY_SIZE(vmxnet3_tq_driver_stats) +
+ ARRAY_SIZE(vmxnet3_rq_dev_stats) +
+ ARRAY_SIZE(vmxnet3_rq_driver_stats) +
+ ARRAY_SIZE(vmxnet3_global_stats);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+
+static int
+vmxnet3_get_regs_len(struct net_device *netdev)
+{
+ return 20 * sizeof(u32);
+}
+
+
+static void
+vmxnet3_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+
+ strlcpy(drvinfo->driver, vmxnet3_driver_name, sizeof(drvinfo->driver));
+ drvinfo->driver[sizeof(drvinfo->driver) - 1] = '\0';
+
+ strlcpy(drvinfo->version, VMXNET3_DRIVER_VERSION_REPORT,
+ sizeof(drvinfo->version));
+ drvinfo->driver[sizeof(drvinfo->version) - 1] = '\0';
+
+ strlcpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+ drvinfo->fw_version[sizeof(drvinfo->fw_version) - 1] = '\0';
+
+ strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
+ ETHTOOL_BUSINFO_LEN);
+ drvinfo->n_stats = vmxnet3_get_sset_count(netdev, ETH_SS_STATS);
+ drvinfo->testinfo_len = 0;
+ drvinfo->eedump_len = 0;
+ drvinfo->regdump_len = vmxnet3_get_regs_len(netdev);
+}
+
+
+static void
+vmxnet3_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
+{
+ if (stringset == ETH_SS_STATS) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++) {
+ memcpy(buf, vmxnet3_tq_dev_stats[i].desc,
+ ETH_GSTRING_LEN);
+ buf += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++) {
+ memcpy(buf, vmxnet3_tq_driver_stats[i].desc,
+ ETH_GSTRING_LEN);
+ buf += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++) {
+ memcpy(buf, vmxnet3_rq_dev_stats[i].desc,
+ ETH_GSTRING_LEN);
+ buf += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++) {
+ memcpy(buf, vmxnet3_rq_driver_stats[i].desc,
+ ETH_GSTRING_LEN);
+ buf += ETH_GSTRING_LEN;
+ }
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++) {
+ memcpy(buf, vmxnet3_global_stats[i].desc,
+ ETH_GSTRING_LEN);
+ buf += ETH_GSTRING_LEN;
+ }
+ }
+}
+
+static u32
+vmxnet3_get_flags(struct net_device *netdev) {
+ return netdev->features;
+}
+
+static int
+vmxnet3_set_flags(struct net_device *netdev, u32 data) {
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ u8 lro_requested = (data & ETH_FLAG_LRO) == 0 ? 0 : 1;
+ u8 lro_present = (netdev->features & NETIF_F_LRO) == 0 ? 0 : 1;
+
+ if (lro_requested ^ lro_present) {
+ /* toggle the LRO feature*/
+ netdev->features ^= NETIF_F_LRO;
+
+ /* update harware LRO capability accordingly */
+ if (lro_requested)
+ adapter->shared->devRead.misc.uptFeatures &= UPT1_F_LRO;
+ else
+ adapter->shared->devRead.misc.uptFeatures &=
+ ~UPT1_F_LRO;
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
+ VMXNET3_CMD_UPDATE_FEATURE);
+ }
+ return 0;
+}
+
+static void
+vmxnet3_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *buf)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ u8 *base;
+ int i;
+
+ VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
+
+ /* this does assume each counter is 64-bit wide */
+
+ base = (u8 *)&adapter->tqd_start->stats;
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
+ *buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset);
+
+ base = (u8 *)&adapter->tx_queue.stats;
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
+ *buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset);
+
+ base = (u8 *)&adapter->rqd_start->stats;
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
+ *buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset);
+
+ base = (u8 *)&adapter->rx_queue.stats;
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
+ *buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset);
+
+ base = (u8 *)adapter;
+ for (i = 0; i < ARRAY_SIZE(vmxnet3_global_stats); i++)
+ *buf++ = *(u64 *)(base + vmxnet3_global_stats[i].offset);
+}
+
+
+static void
+vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ u32 *buf = p;
+
+ memset(p, 0, vmxnet3_get_regs_len(netdev));
+
+ regs->version = 1;
+
+ /* Update vmxnet3_get_regs_len if we want to dump more registers */
+
+ /* make each ring use multiple of 16 bytes */
+ buf[0] = adapter->tx_queue.tx_ring.next2fill;
+ buf[1] = adapter->tx_queue.tx_ring.next2comp;
+ buf[2] = adapter->tx_queue.tx_ring.gen;
+ buf[3] = 0;
+
+ buf[4] = adapter->tx_queue.comp_ring.next2proc;
+ buf[5] = adapter->tx_queue.comp_ring.gen;
+ buf[6] = adapter->tx_queue.stopped;
+ buf[7] = 0;
+
+ buf[8] = adapter->rx_queue.rx_ring[0].next2fill;
+ buf[9] = adapter->rx_queue.rx_ring[0].next2comp;
+ buf[10] = adapter->rx_queue.rx_ring[0].gen;
+ buf[11] = 0;
+
+ buf[12] = adapter->rx_queue.rx_ring[1].next2fill;
+ buf[13] = adapter->rx_queue.rx_ring[1].next2comp;
+ buf[14] = adapter->rx_queue.rx_ring[1].gen;
+ buf[15] = 0;
+
+ buf[16] = adapter->rx_queue.comp_ring.next2proc;
+ buf[17] = adapter->rx_queue.comp_ring.gen;
+ buf[18] = 0;
+ buf[19] = 0;
+}
+
+
+static void
+vmxnet3_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+
+ wol->supported = WAKE_UCAST | WAKE_ARP | WAKE_MAGIC;
+ wol->wolopts = adapter->wol;
+}
+
+
+static int
+vmxnet3_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+
+ if (wol->wolopts & (WAKE_PHY | WAKE_MCAST | WAKE_BCAST |
+ WAKE_MAGICSECURE)) {
+ return -EOPNOTSUPP;
+ }
+
+ adapter->wol = wol->wolopts;
+
+ device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+
+ return 0;
+}
+
+
+static int
+vmxnet3_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+
+ ecmd->supported = SUPPORTED_10000baseT_Full | SUPPORTED_1000baseT_Full |
+ SUPPORTED_TP;
+ ecmd->advertising = ADVERTISED_TP;
+ ecmd->port = PORT_TP;
+ ecmd->transceiver = XCVR_INTERNAL;
+
+ if (adapter->link_speed) {
+ ecmd->speed = adapter->link_speed;
+ ecmd->duplex = DUPLEX_FULL;
+ } else {
+ ecmd->speed = -1;
+ ecmd->duplex = -1;
+ }
+ return 0;
+}
+
+
+static void
+vmxnet3_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *param)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+
+ param->rx_max_pending = VMXNET3_RX_RING_MAX_SIZE;
+ param->tx_max_pending = VMXNET3_TX_RING_MAX_SIZE;
+ param->rx_mini_max_pending = 0;
+ param->rx_jumbo_max_pending = 0;
+
+ param->rx_pending = adapter->rx_queue.rx_ring[0].size;
+ param->tx_pending = adapter->tx_queue.tx_ring.size;
+ param->rx_mini_pending = 0;
+ param->rx_jumbo_pending = 0;
+}
+
+
+static int
+vmxnet3_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *param)
+{
+ struct vmxnet3_adapter *adapter = netdev_priv(netdev);
+ u32 new_tx_ring_size, new_rx_ring_size;
+ u32 sz;
+ int err = 0;
+
+ if (param->tx_pending == 0 || param->tx_pending >
+ VMXNET3_TX_RING_MAX_SIZE)
+ return -EINVAL;
+
+ if (param->rx_pending == 0 || param->rx_pending >
+ VMXNET3_RX_RING_MAX_SIZE)
+ return -EINVAL;
+
+
+ /* round it up to a multiple of VMXNET3_RING_SIZE_ALIGN */
+ new_tx_ring_size = (param->tx_pending + VMXNET3_RING_SIZE_MASK) &
+ ~VMXNET3_RING_SIZE_MASK;
+ new_tx_ring_size = min_t(u32, new_tx_ring_size,
+ VMXNET3_TX_RING_MAX_SIZE);
+ if (new_tx_ring_size > VMXNET3_TX_RING_MAX_SIZE || (new_tx_ring_size %
+ VMXNET3_RING_SIZE_ALIGN) != 0)
+ return -EINVAL;
+
+ /* ring0 has to be a multiple of
+ * rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN
+ */
+ sz = adapter->rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN;
+ new_rx_ring_size = (param->rx_pending + sz - 1) / sz * sz;
+ new_rx_ring_size = min_t(u32, new_rx_ring_size,
+ VMXNET3_RX_RING_MAX_SIZE / sz * sz);
+ if (new_rx_ring_size > VMXNET3_RX_RING_MAX_SIZE || (new_rx_ring_size %
+ sz) != 0)
+ return -EINVAL;
+
+ if (new_tx_ring_size == adapter->tx_queue.tx_ring.size &&
+ new_rx_ring_size == adapter->rx_queue.rx_ring[0].size) {
+ return 0;
+ }
+
+ /*
+ * Reset_work may be in the middle of resetting the device, wait for its
+ * completion.
+ */
+ while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state))
+ msleep(1);
+
+ if (netif_running(netdev)) {
+ vmxnet3_quiesce_dev(adapter);
+ vmxnet3_reset_dev(adapter);
+
+ /* recreate the rx queue and the tx queue based on the
+ * new sizes */
+ vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
+ vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
+
+ err = vmxnet3_create_queues(adapter, new_tx_ring_size,
+ new_rx_ring_size, VMXNET3_DEF_RX_RING_SIZE);
+ if (err) {
+ /* failed, most likely because of OOM, try default
+ * size */
+ printk(KERN_ERR "%s: failed to apply new sizes, try the"
+ " default ones\n", netdev->name);
+ err = vmxnet3_create_queues(adapter,
+ VMXNET3_DEF_TX_RING_SIZE,
+ VMXNET3_DEF_RX_RING_SIZE,
+ VMXNET3_DEF_RX_RING_SIZE);
+ if (err) {
+ printk(KERN_ERR "%s: failed to create queues "
+ "with default sizes. Closing it\n",
+ netdev->name);
+ goto out;
+ }
+ }
+
+ err = vmxnet3_activate_dev(adapter);
+ if (err)
+ printk(KERN_ERR "%s: failed to re-activate, error %d."
+ " Closing it\n", netdev->name, err);
+ }
+
+out:
+ clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
+ if (err)
+ vmxnet3_force_close(adapter);
+
+ return err;
+}
+
+
+static struct ethtool_ops vmxnet3_ethtool_ops = {
+ .get_settings = vmxnet3_get_settings,
+ .get_drvinfo = vmxnet3_get_drvinfo,
+ .get_regs_len = vmxnet3_get_regs_len,
+ .get_regs = vmxnet3_get_regs,
+ .get_wol = vmxnet3_get_wol,
+ .set_wol = vmxnet3_set_wol,
+ .get_link = ethtool_op_get_link,
+ .get_rx_csum = vmxnet3_get_rx_csum,
+ .set_rx_csum = vmxnet3_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_hw_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+ .get_strings = vmxnet3_get_strings,
+ .get_flags = vmxnet3_get_flags,
+ .set_flags = vmxnet3_set_flags,
+ .get_sset_count = vmxnet3_get_sset_count,
+ .get_ethtool_stats = vmxnet3_get_ethtool_stats,
+ .get_ringparam = vmxnet3_get_ringparam,
+ .set_ringparam = vmxnet3_set_ringparam,
+};
+
+void vmxnet3_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &vmxnet3_ethtool_ops);
+}
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
new file mode 100644
index 000000000000..6bb91576e999
--- /dev/null
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -0,0 +1,389 @@
+/*
+ * Linux driver for VMware's vmxnet3 ethernet NIC.
+ *
+ * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; version 2 of the License and no 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
+ *
+ * Maintained by: Shreyas Bhatewara <pv-drivers@vmware.com>
+ *
+ */
+
+#ifndef _VMXNET3_INT_H
+#define _VMXNET3_INT_H
+
+#include <linux/types.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/ethtool.h>
+#include <linux/compiler.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/uaccess.h>
+#include <asm/dma.h>
+#include <asm/page.h>
+
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/in.h>
+#include <linux/etherdevice.h>
+#include <asm/checksum.h>
+#include <linux/if_vlan.h>
+#include <linux/if_arp.h>
+#include <linux/inetdevice.h>
+#include <linux/dst.h>
+
+#include "vmxnet3_defs.h"
+
+#ifdef DEBUG
+# define VMXNET3_DRIVER_VERSION_REPORT VMXNET3_DRIVER_VERSION_STRING"-NAPI(debug)"
+#else
+# define VMXNET3_DRIVER_VERSION_REPORT VMXNET3_DRIVER_VERSION_STRING"-NAPI"
+#endif
+
+
+/*
+ * Version numbers
+ */
+#define VMXNET3_DRIVER_VERSION_STRING "1.0.5.0-k"
+
+/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
+#define VMXNET3_DRIVER_VERSION_NUM 0x01000500
+
+
+/*
+ * Capabilities
+ */
+
+enum {
+ VMNET_CAP_SG = 0x0001, /* Can do scatter-gather transmits. */
+ VMNET_CAP_IP4_CSUM = 0x0002, /* Can checksum only TCP/UDP over
+ * IPv4 */
+ VMNET_CAP_HW_CSUM = 0x0004, /* Can checksum all packets. */
+ VMNET_CAP_HIGH_DMA = 0x0008, /* Can DMA to high memory. */
+ VMNET_CAP_TOE = 0x0010, /* Supports TCP/IP offload. */
+ VMNET_CAP_TSO = 0x0020, /* Supports TCP Segmentation
+ * offload */
+ VMNET_CAP_SW_TSO = 0x0040, /* Supports SW TCP Segmentation */
+ VMNET_CAP_VMXNET_APROM = 0x0080, /* Vmxnet APROM support */
+ VMNET_CAP_HW_TX_VLAN = 0x0100, /* Can we do VLAN tagging in HW */
+ VMNET_CAP_HW_RX_VLAN = 0x0200, /* Can we do VLAN untagging in HW */
+ VMNET_CAP_SW_VLAN = 0x0400, /* VLAN tagging/untagging in SW */
+ VMNET_CAP_WAKE_PCKT_RCV = 0x0800, /* Can wake on network packet recv? */
+ VMNET_CAP_ENABLE_INT_INLINE = 0x1000, /* Enable Interrupt Inline */
+ VMNET_CAP_ENABLE_HEADER_COPY = 0x2000, /* copy header for vmkernel */
+ VMNET_CAP_TX_CHAIN = 0x4000, /* Guest can use multiple tx entries
+ * for a pkt */
+ VMNET_CAP_RX_CHAIN = 0x8000, /* pkt can span multiple rx entries */
+ VMNET_CAP_LPD = 0x10000, /* large pkt delivery */
+ VMNET_CAP_BPF = 0x20000, /* BPF Support in VMXNET Virtual HW*/
+ VMNET_CAP_SG_SPAN_PAGES = 0x40000, /* Scatter-gather can span multiple*/
+ /* pages transmits */
+ VMNET_CAP_IP6_CSUM = 0x80000, /* Can do IPv6 csum offload. */
+ VMNET_CAP_TSO6 = 0x100000, /* TSO seg. offload for IPv6 pkts. */
+ VMNET_CAP_TSO256k = 0x200000, /* Can do TSO seg offload for */
+ /* pkts up to 256kB. */
+ VMNET_CAP_UPT = 0x400000 /* Support UPT */
+};
+
+/*
+ * PCI vendor and device IDs.
+ */
+#define PCI_VENDOR_ID_VMWARE 0x15AD
+#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0
+#define MAX_ETHERNET_CARDS 10
+#define MAX_PCI_PASSTHRU_DEVICE 6
+
+struct vmxnet3_cmd_ring {
+ union Vmxnet3_GenericDesc *base;
+ u32 size;
+ u32 next2fill;
+ u32 next2comp;
+ u8 gen;
+ dma_addr_t basePA;
+};
+
+static inline void
+vmxnet3_cmd_ring_adv_next2fill(struct vmxnet3_cmd_ring *ring)
+{
+ ring->next2fill++;
+ if (unlikely(ring->next2fill == ring->size)) {
+ ring->next2fill = 0;
+ VMXNET3_FLIP_RING_GEN(ring->gen);
+ }
+}
+
+static inline void
+vmxnet3_cmd_ring_adv_next2comp(struct vmxnet3_cmd_ring *ring)
+{
+ VMXNET3_INC_RING_IDX_ONLY(ring->next2comp, ring->size);
+}
+
+static inline int
+vmxnet3_cmd_ring_desc_avail(struct vmxnet3_cmd_ring *ring)
+{
+ return (ring->next2comp > ring->next2fill ? 0 : ring->size) +
+ ring->next2comp - ring->next2fill - 1;
+}
+
+struct vmxnet3_comp_ring {
+ union Vmxnet3_GenericDesc *base;
+ u32 size;
+ u32 next2proc;
+ u8 gen;
+ u8 intr_idx;
+ dma_addr_t basePA;
+};
+
+static inline void
+vmxnet3_comp_ring_adv_next2proc(struct vmxnet3_comp_ring *ring)
+{
+ ring->next2proc++;
+ if (unlikely(ring->next2proc == ring->size)) {
+ ring->next2proc = 0;
+ VMXNET3_FLIP_RING_GEN(ring->gen);
+ }
+}
+
+struct vmxnet3_tx_data_ring {
+ struct Vmxnet3_TxDataDesc *base;
+ u32 size;
+ dma_addr_t basePA;
+};
+
+enum vmxnet3_buf_map_type {
+ VMXNET3_MAP_INVALID = 0,
+ VMXNET3_MAP_NONE,
+ VMXNET3_MAP_SINGLE,
+ VMXNET3_MAP_PAGE,
+};
+
+struct vmxnet3_tx_buf_info {
+ u32 map_type;
+ u16 len;
+ u16 sop_idx;
+ dma_addr_t dma_addr;
+ struct sk_buff *skb;
+};
+
+struct vmxnet3_tq_driver_stats {
+ u64 drop_total; /* # of pkts dropped by the driver, the
+ * counters below track droppings due to
+ * different reasons
+ */
+ u64 drop_too_many_frags;
+ u64 drop_oversized_hdr;
+ u64 drop_hdr_inspect_err;
+ u64 drop_tso;
+
+ u64 tx_ring_full;
+ u64 linearized; /* # of pkts linearized */
+ u64 copy_skb_header; /* # of times we have to copy skb header */
+ u64 oversized_hdr;
+};
+
+struct vmxnet3_tx_ctx {
+ bool ipv4;
+ u16 mss;
+ u32 eth_ip_hdr_size; /* only valid for pkts requesting tso or csum
+ * offloading
+ */
+ u32 l4_hdr_size; /* only valid if mss != 0 */
+ u32 copy_size; /* # of bytes copied into the data ring */
+ union Vmxnet3_GenericDesc *sop_txd;
+ union Vmxnet3_GenericDesc *eop_txd;
+};
+
+struct vmxnet3_tx_queue {
+ spinlock_t tx_lock;
+ struct vmxnet3_cmd_ring tx_ring;
+ struct vmxnet3_tx_buf_info *buf_info;
+ struct vmxnet3_tx_data_ring data_ring;
+ struct vmxnet3_comp_ring comp_ring;
+ struct Vmxnet3_TxQueueCtrl *shared;
+ struct vmxnet3_tq_driver_stats stats;
+ bool stopped;
+ int num_stop; /* # of times the queue is
+ * stopped */
+} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+
+enum vmxnet3_rx_buf_type {
+ VMXNET3_RX_BUF_NONE = 0,
+ VMXNET3_RX_BUF_SKB = 1,
+ VMXNET3_RX_BUF_PAGE = 2
+};
+
+struct vmxnet3_rx_buf_info {
+ enum vmxnet3_rx_buf_type buf_type;
+ u16 len;
+ union {
+ struct sk_buff *skb;
+ struct page *page;
+ };
+ dma_addr_t dma_addr;
+};
+
+struct vmxnet3_rx_ctx {
+ struct sk_buff *skb;
+ u32 sop_idx;
+};
+
+struct vmxnet3_rq_driver_stats {
+ u64 drop_total;
+ u64 drop_err;
+ u64 drop_fcs;
+ u64 rx_buf_alloc_failure;
+};
+
+struct vmxnet3_rx_queue {
+ struct vmxnet3_cmd_ring rx_ring[2];
+ struct vmxnet3_comp_ring comp_ring;
+ struct vmxnet3_rx_ctx rx_ctx;
+ u32 qid; /* rqID in RCD for buffer from 1st ring */
+ u32 qid2; /* rqID in RCD for buffer from 2nd ring */
+ u32 uncommitted[2]; /* # of buffers allocated since last RXPROD
+ * update */
+ struct vmxnet3_rx_buf_info *buf_info[2];
+ struct Vmxnet3_RxQueueCtrl *shared;
+ struct vmxnet3_rq_driver_stats stats;
+} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+
+#define VMXNET3_LINUX_MAX_MSIX_VECT 1
+
+struct vmxnet3_intr {
+ enum vmxnet3_intr_mask_mode mask_mode;
+ enum vmxnet3_intr_type type; /* MSI-X, MSI, or INTx? */
+ u8 num_intrs; /* # of intr vectors */
+ u8 event_intr_idx; /* idx of the intr vector for event */
+ u8 mod_levels[VMXNET3_LINUX_MAX_MSIX_VECT]; /* moderation level */
+#ifdef CONFIG_PCI_MSI
+ struct msix_entry msix_entries[VMXNET3_LINUX_MAX_MSIX_VECT];
+#endif
+};
+
+#define VMXNET3_STATE_BIT_RESETTING 0
+#define VMXNET3_STATE_BIT_QUIESCED 1
+struct vmxnet3_adapter {
+ struct vmxnet3_tx_queue tx_queue;
+ struct vmxnet3_rx_queue rx_queue;
+ struct napi_struct napi;
+ struct vlan_group *vlan_grp;
+
+ struct vmxnet3_intr intr;
+
+ struct Vmxnet3_DriverShared *shared;
+ struct Vmxnet3_PMConf *pm_conf;
+ struct Vmxnet3_TxQueueDesc *tqd_start; /* first tx queue desc */
+ struct Vmxnet3_RxQueueDesc *rqd_start; /* first rx queue desc */
+ struct net_device *netdev;
+ struct pci_dev *pdev;
+
+ u8 *hw_addr0; /* for BAR 0 */
+ u8 *hw_addr1; /* for BAR 1 */
+
+ /* feature control */
+ bool rxcsum;
+ bool lro;
+ bool jumbo_frame;
+
+ /* rx buffer related */
+ unsigned skb_buf_size;
+ int rx_buf_per_pkt; /* only apply to the 1st ring */
+ dma_addr_t shared_pa;
+ dma_addr_t queue_desc_pa;
+
+ /* Wake-on-LAN */
+ u32 wol;
+
+ /* Link speed */
+ u32 link_speed; /* in mbps */
+
+ u64 tx_timeout_count;
+ struct work_struct work;
+
+ unsigned long state; /* VMXNET3_STATE_BIT_xxx */
+
+ int dev_number;
+};
+
+#define VMXNET3_WRITE_BAR0_REG(adapter, reg, val) \
+ writel((val), (adapter)->hw_addr0 + (reg))
+#define VMXNET3_READ_BAR0_REG(adapter, reg) \
+ readl((adapter)->hw_addr0 + (reg))
+
+#define VMXNET3_WRITE_BAR1_REG(adapter, reg, val) \
+ writel((val), (adapter)->hw_addr1 + (reg))
+#define VMXNET3_READ_BAR1_REG(adapter, reg) \
+ readl((adapter)->hw_addr1 + (reg))
+
+#define VMXNET3_WAKE_QUEUE_THRESHOLD(tq) (5)
+#define VMXNET3_RX_ALLOC_THRESHOLD(rq, ring_idx, adapter) \
+ ((rq)->rx_ring[ring_idx].size >> 3)
+
+#define VMXNET3_GET_ADDR_LO(dma) ((u32)(dma))
+#define VMXNET3_GET_ADDR_HI(dma) ((u32)(((u64)(dma)) >> 32))
+
+/* must be a multiple of VMXNET3_RING_SIZE_ALIGN */
+#define VMXNET3_DEF_TX_RING_SIZE 512
+#define VMXNET3_DEF_RX_RING_SIZE 256
+
+#define VMXNET3_MAX_ETH_HDR_SIZE 22
+#define VMXNET3_MAX_SKB_BUF_SIZE (3*1024)
+
+int
+vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter);
+
+int
+vmxnet3_activate_dev(struct vmxnet3_adapter *adapter);
+
+void
+vmxnet3_force_close(struct vmxnet3_adapter *adapter);
+
+void
+vmxnet3_reset_dev(struct vmxnet3_adapter *adapter);
+
+void
+vmxnet3_tq_destroy(struct vmxnet3_tx_queue *tq,
+ struct vmxnet3_adapter *adapter);
+
+void
+vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq,
+ struct vmxnet3_adapter *adapter);
+
+int
+vmxnet3_create_queues(struct vmxnet3_adapter *adapter,
+ u32 tx_ring_size, u32 rx_ring_size, u32 rx_ring2_size);
+
+extern void vmxnet3_set_ethtool_ops(struct net_device *netdev);
+extern struct net_device_stats *vmxnet3_get_stats(struct net_device *netdev);
+
+extern char vmxnet3_driver_name[];
+#endif
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/c101.c b/drivers/net/wan/c101.c
index 9693b0fd323d..0bd898c94759 100644
--- a/drivers/net/wan/c101.c
+++ b/drivers/net/wan/c101.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/capability.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/string.h>
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 66360a2a14c2..e2c33c06190b 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -76,6 +76,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/fs.h>
diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
index 2573c18b6aa5..cd8cb95c5bd7 100644
--- a/drivers/net/wan/cycx_x25.c
+++ b/drivers/net/wan/cycx_x25.c
@@ -84,6 +84,7 @@
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/module.h>
#include <linux/string.h> /* inline memset(), etc. */
+#include <linux/sched.h>
#include <linux/slab.h> /* kmalloc(), kfree() */
#include <linux/stddef.h> /* offsetof(), etc. */
#include <linux/wanrouter.h> /* WAN router definitions */
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index 81c8aec9df92..07d00b4cf48a 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -81,6 +81,7 @@
*/
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/list.h>
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 3e90eb816181..beda387f2fc7 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/pci.h>
+#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/if.h>
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index cf5fd17ad707..f1bff98acd1f 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -58,8 +58,7 @@ struct cisco_state {
spinlock_t lock;
unsigned long last_poll;
int up;
- int request_sent;
- u32 txseq; /* TX sequence number */
+ u32 txseq; /* TX sequence number, 0 = none */
u32 rxseq; /* RX sequence number */
};
@@ -163,6 +162,7 @@ static int cisco_rx(struct sk_buff *skb)
struct cisco_packet *cisco_data;
struct in_device *in_dev;
__be32 addr, mask;
+ u32 ack;
if (skb->len < sizeof(struct hdlc_header))
goto rx_error;
@@ -223,8 +223,10 @@ static int cisco_rx(struct sk_buff *skb)
case CISCO_KEEPALIVE_REQ:
spin_lock(&st->lock);
st->rxseq = ntohl(cisco_data->par1);
- if (st->request_sent &&
- ntohl(cisco_data->par2) == st->txseq) {
+ ack = ntohl(cisco_data->par2);
+ if (ack && (ack == st->txseq ||
+ /* our current REQ may be in transit */
+ ack == st->txseq - 1)) {
st->last_poll = jiffies;
if (!st->up) {
u32 sec, min, hrs, days;
@@ -275,7 +277,6 @@ static void cisco_timer(unsigned long arg)
cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, htonl(++st->txseq),
htonl(st->rxseq));
- st->request_sent = 1;
spin_unlock(&st->lock);
st->timer.expires = jiffies + st->settings.interval * HZ;
@@ -293,9 +294,7 @@ static void cisco_start(struct net_device *dev)
unsigned long flags;
spin_lock_irqsave(&st->lock, flags);
- st->up = 0;
- st->request_sent = 0;
- st->txseq = st->rxseq = 0;
+ st->up = st->txseq = st->rxseq = 0;
spin_unlock_irqrestore(&st->lock, flags);
init_timer(&st->timer);
@@ -317,8 +316,7 @@ static void cisco_stop(struct net_device *dev)
spin_lock_irqsave(&st->lock, flags);
netif_dormant_on(dev);
- st->up = 0;
- st->request_sent = 0;
+ st->up = st->txseq = 0;
spin_unlock_irqrestore(&st->lock, flags);
}
diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c
index 83da596e2052..58c66819f39b 100644
--- a/drivers/net/wan/n2.c
+++ b/drivers/net/wan/n2.c
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/capability.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/fcntl.h>
diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c
index a52f29c72c33..f1340faaf022 100644
--- a/drivers/net/wan/pci200syn.c
+++ b/drivers/net/wan/pci200syn.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
+#include <linux/capability.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/fcntl.h>
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index d7a764a2fc1a..85f8bf4112c1 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 pre 802.11 and 802.11 wireless
@@ -67,6 +68,8 @@ config WAVELAN
tristate "AT&T/Lucent old WaveLAN & DEC RoamAbout DS ISA support"
depends on ISA && WLAN_PRE80211
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
@@ -90,6 +93,8 @@ config PCMCIA_WAVELAN
tristate "AT&T/Lucent old WaveLAN Pcmcia wireless support"
depends on PCMCIA && WLAN_PRE80211
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
@@ -102,6 +107,7 @@ config PCMCIA_NETWAVE
tristate "Xircom Netwave AirSurfer Pcmcia wireless support"
depends on PCMCIA && WLAN_PRE80211
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.
@@ -123,6 +129,8 @@ config PCMCIA_RAYCS
tristate "Aviator/Raytheon 2.4GHz wireless support"
depends on PCMCIA && WLAN_80211
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.
@@ -132,46 +140,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"
- depends on WLAN_80211
- 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 WLAN_80211 && MAC80211
@@ -190,6 +158,8 @@ config AIRO
depends on ISA_DMA_API && WLAN_80211 && (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.
@@ -207,6 +177,7 @@ config ATMEL
tristate "Atmel at76c50x chipset 802.11b support"
depends on (PCI || PCMCIA) && WLAN_80211
select WIRELESS_EXT
+ select WEXT_PRIV
select FW_LOADER
select CRC32
---help---
@@ -266,18 +237,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 && WLAN_80211
- 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 && WLAN_80211
+ 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 && WLAN_80211
select WIRELESS_EXT
+ select WEXT_SPY
+ select WEXT_PRIV
select FW_LOADER
---help---
This enables support for FullMAC PCI/Cardbus prism54 devices. This
@@ -300,6 +274,7 @@ config USB_ZD1201
tristate "USB ZD1201 based Wireless device support"
depends on USB && WLAN_80211
select WIRELESS_EXT
+ select WEXT_PRIV
select FW_LOADER
---help---
Say Y if you want to use wireless LAN adapters based on the ZyDAS
@@ -476,17 +451,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/adm8211.h b/drivers/net/wireless/adm8211.h
index 4f6ab1322189..b07e4d3a6b4d 100644
--- a/drivers/net/wireless/adm8211.h
+++ b/drivers/net/wireless/adm8211.h
@@ -266,7 +266,7 @@ do { \
#define ADM8211_SYNCTL_CS1 (1 << 28)
#define ADM8211_SYNCTL_CAL (1 << 27)
#define ADM8211_SYNCTL_SELCAL (1 << 26)
-#define ADM8211_SYNCTL_RFtype ((1 << 24) || (1 << 23) || (1 << 22))
+#define ADM8211_SYNCTL_RFtype ((1 << 24) | (1 << 23) | (1 << 22))
#define ADM8211_SYNCTL_RFMD (1 << 22)
#define ADM8211_SYNCTL_GENERAL (0x7 << 22)
/* SYNCTL 21:0 Data (Si4126: 18-bit data, 4-bit address) */
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 7116a1aa20ce..e265ba14054b 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -5660,7 +5660,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..ec034af26980 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];
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..88113148331c 100644
--- a/drivers/net/wireless/ath/ar9170/hw.h
+++ b/drivers/net/wireless/ath/ar9170/hw.h
@@ -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..de0ba2bf7691 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -1952,6 +1952,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 +1963,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 +2132,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 +2192,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/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..b14ba07e9157 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];
@@ -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/b43/b43.h b/drivers/net/wireless/b43/b43.h
index fa1549a03c71..660716214d49 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -607,82 +607,7 @@ struct b43_qos_params {
struct ieee80211_tx_queue_params p;
};
-struct b43_wldev;
-
-/* 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 */
- struct b43_wldev *current_dev;
- /* Pointer to the ieee80211 hardware data structure */
- struct ieee80211_hw *hw;
-
- /* Global driver mutex. Every operation must run with this mutex locked. */
- struct mutex mutex;
- /* Hard-IRQ spinlock. This lock protects things used in the hard-IRQ
- * handler, only. This basically is just the IRQ mask register. */
- spinlock_t hardirq_lock;
-
- /* The number of queues that were registered with the mac80211 subsystem
- * initially. This is a backup copy of hw->queues in case hw->queues has
- * to be dynamically lowered at runtime (Firmware does not support QoS).
- * hw->queues has to be restored to the original value before unregistering
- * from the mac80211 subsystem. */
- u16 mac80211_initially_registered_queues;
-
- /* We can only have one operating interface (802.11 core)
- * at a time. General information about this interface follows.
- */
-
- struct ieee80211_vif *vif;
- /* The MAC address of the operating interface. */
- u8 mac_addr[ETH_ALEN];
- /* Current BSSID */
- u8 bssid[ETH_ALEN];
- /* Interface type. (NL80211_IFTYPE_XXX) */
- int if_type;
- /* Is the card operating in AP, STA or IBSS mode? */
- bool operating;
- /* filter flags */
- unsigned int filter_flags;
- /* Stats about the wireless interface */
- struct ieee80211_low_level_stats ieee_stats;
-
-#ifdef CONFIG_B43_HWRNG
- struct hwrng rng;
- bool rng_initialized;
- char rng_name[30 + 1];
-#endif /* CONFIG_B43_HWRNG */
-
- /* List of all wireless devices on this chip */
- struct list_head devlist;
- u8 nr_devs;
-
- bool radiotap_enabled;
- bool radio_enabled;
-
- /* The beacon we are currently using (AP or IBSS mode). */
- struct sk_buff *current_beacon;
- bool beacon0_uploaded;
- bool beacon1_uploaded;
- bool beacon_templates_virgin; /* Never wrote the templates? */
- struct work_struct beacon_update_trigger;
-
- /* The current QOS parameters for the 4 queues. */
- struct b43_qos_params qos_params[4];
-
- /* Work for adjustment of the transmission power.
- * This is scheduled when we determine that the actual TX output
- * power doesn't match what we want. */
- struct work_struct txpower_adjust_work;
-
- /* Packet transmit work */
- struct work_struct tx_work;
- /* Queue of packets to be transmitted. */
- struct sk_buff_head tx_queue;
-
- /* The device LEDs. */
- struct b43_leds leds;
-};
+struct b43_wl;
/* The type of the firmware file. */
enum b43_firmware_file_type {
@@ -824,6 +749,97 @@ 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 */
+ struct b43_wldev *current_dev;
+ /* Pointer to the ieee80211 hardware data structure */
+ struct ieee80211_hw *hw;
+
+ /* Global driver mutex. Every operation must run with this mutex locked. */
+ struct mutex mutex;
+ /* Hard-IRQ spinlock. This lock protects things used in the hard-IRQ
+ * handler, only. This basically is just the IRQ mask register. */
+ spinlock_t hardirq_lock;
+
+ /* The number of queues that were registered with the mac80211 subsystem
+ * initially. This is a backup copy of hw->queues in case hw->queues has
+ * to be dynamically lowered at runtime (Firmware does not support QoS).
+ * hw->queues has to be restored to the original value before unregistering
+ * from the mac80211 subsystem. */
+ u16 mac80211_initially_registered_queues;
+
+ /* We can only have one operating interface (802.11 core)
+ * at a time. General information about this interface follows.
+ */
+
+ struct ieee80211_vif *vif;
+ /* The MAC address of the operating interface. */
+ u8 mac_addr[ETH_ALEN];
+ /* Current BSSID */
+ u8 bssid[ETH_ALEN];
+ /* Interface type. (NL80211_IFTYPE_XXX) */
+ int if_type;
+ /* Is the card operating in AP, STA or IBSS mode? */
+ bool operating;
+ /* filter flags */
+ unsigned int filter_flags;
+ /* Stats about the wireless interface */
+ struct ieee80211_low_level_stats ieee_stats;
+
+#ifdef CONFIG_B43_HWRNG
+ struct hwrng rng;
+ bool rng_initialized;
+ char rng_name[30 + 1];
+#endif /* CONFIG_B43_HWRNG */
+
+ /* List of all wireless devices on this chip */
+ struct list_head devlist;
+ u8 nr_devs;
+
+ bool radiotap_enabled;
+ bool radio_enabled;
+
+ /* The beacon we are currently using (AP or IBSS mode). */
+ struct sk_buff *current_beacon;
+ bool beacon0_uploaded;
+ bool beacon1_uploaded;
+ bool beacon_templates_virgin; /* Never wrote the templates? */
+ struct work_struct beacon_update_trigger;
+
+ /* The current QOS parameters for the 4 queues. */
+ struct b43_qos_params qos_params[4];
+
+ /* Work for adjustment of the transmission power.
+ * This is scheduled when we determine that the actual TX output
+ * power doesn't match what we want. */
+ struct work_struct txpower_adjust_work;
+
+ /* Packet transmit work */
+ struct work_struct tx_work;
+ /* Queue of packets to be transmitted. */
+ struct sk_buff_head tx_queue;
+
+ /* The device LEDs. */
+ 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];
+#endif /* CONFIG_B43_PIO */
+};
+
static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw)
{
return hw->priv;
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
index fbe3d4f62ce2..1e8dba488004 100644
--- a/drivers/net/wireless/b43/leds.c
+++ b/drivers/net/wireless/b43/leds.c
@@ -348,9 +348,9 @@ void b43_leds_register(struct b43_wldev *dev)
}
}
-void b43_leds_unregister(struct b43_wldev *dev)
+void b43_leds_unregister(struct b43_wl *wl)
{
- struct b43_leds *leds = &dev->wl->leds;
+ struct b43_leds *leds = &wl->leds;
b43_unregister_led(&leds->led_tx);
b43_unregister_led(&leds->led_rx);
diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h
index 9592e4c5a5f5..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
@@ -60,7 +61,7 @@ enum b43_led_behaviour {
};
void b43_leds_register(struct b43_wldev *dev);
-void b43_leds_unregister(struct b43_wldev *dev);
+void b43_leds_unregister(struct b43_wl *wl);
void b43_leds_init(struct b43_wldev *dev);
void b43_leds_exit(struct b43_wldev *dev);
void b43_leds_stop(struct b43_wldev *dev);
@@ -76,7 +77,7 @@ struct b43_leds {
static inline void b43_leds_register(struct b43_wldev *dev)
{
}
-static inline void b43_leds_unregister(struct b43_wldev *dev)
+static inline void b43_leds_unregister(struct b43_wl *wl)
{
}
static inline void b43_leds_init(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 9b907a36bb8c..751017b4c3d3 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3874,6 +3874,7 @@ static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev)
{
struct b43_wl *wl = dev->wl;
struct b43_wldev *orig_dev;
+ u32 mask;
redo:
if (!dev || b43_status(dev) < B43_STAT_STARTED)
@@ -3920,7 +3921,8 @@ redo:
goto redo;
return dev;
}
- B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK));
+ mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+ B43_WARN_ON(mask != 0xFFFFFFFF && mask);
/* Drain the TX queue */
while (skb_queue_len(&wl->tx_queue))
@@ -4499,6 +4501,7 @@ 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);
@@ -4668,7 +4671,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;
@@ -4801,7 +4804,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
@@ -4997,7 +5000,7 @@ static void b43_remove(struct ssb_device *dev)
if (list_empty(&wl->devlist)) {
b43_rng_exit(wl);
- b43_leds_unregister(wldev);
+ b43_leds_unregister(wl);
/* Last core on the chip unregistered.
* We can destroy common struct b43_wl.
*/
diff --git a/drivers/net/wireless/b43/phy_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 9c1397996e0a..9b9044400218 100644
--- a/drivers/net/wireless/b43/pio.c
+++ b/drivers/net/wireless/b43/pio.c
@@ -30,6 +30,7 @@
#include "xmit.h"
#include <linux/delay.h>
+#include <linux/sched.h>
static u16 generate_cookie(struct b43_pio_txqueue *q,
@@ -331,6 +332,7 @@ static u16 tx_write_2byte_queue(struct b43_pio_txqueue *q,
unsigned int data_len)
{
struct b43_wldev *dev = q->dev;
+ struct b43_wl *wl = dev->wl;
const u8 *data = _data;
ctl |= B43_PIO_TXCTL_WRITELO | B43_PIO_TXCTL_WRITEHI;
@@ -340,13 +342,12 @@ 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[2] = { 0, };
-
/* Write the last byte. */
ctl &= ~B43_PIO_TXCTL_WRITEHI;
b43_piotx_write16(q, B43_PIO_TXCTL, ctl);
- tail[0] = data[data_len - 1];
- ssb_block_write(dev->dev, tail, 2,
+ wl->tx_tail[0] = data[data_len - 1];
+ wl->tx_tail[1] = 0;
+ ssb_block_write(dev->dev, wl->tx_tail, 2,
q->mmio_base + B43_PIO_TXDATA,
sizeof(u16));
}
@@ -381,6 +382,7 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
unsigned int data_len)
{
struct b43_wldev *dev = q->dev;
+ struct b43_wl *wl = dev->wl;
const u8 *data = _data;
ctl |= B43_PIO8_TXCTL_0_7 | B43_PIO8_TXCTL_8_15 |
@@ -391,29 +393,31 @@ static u32 tx_write_4byte_queue(struct b43_pio_txqueue *q,
q->mmio_base + B43_PIO8_TXDATA,
sizeof(u32));
if (data_len & 3) {
- u8 tail[4] = { 0, };
-
+ wl->tx_tail[3] = 0;
/* 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;
- tail[0] = data[data_len - 3];
- tail[1] = data[data_len - 2];
- tail[2] = data[data_len - 1];
+ wl->tx_tail[0] = data[data_len - 3];
+ wl->tx_tail[1] = data[data_len - 2];
+ wl->tx_tail[2] = data[data_len - 1];
break;
case 2:
ctl |= B43_PIO8_TXCTL_8_15;
- tail[0] = data[data_len - 2];
- tail[1] = data[data_len - 1];
+ wl->tx_tail[0] = data[data_len - 2];
+ wl->tx_tail[1] = data[data_len - 1];
+ wl->tx_tail[2] = 0;
break;
case 1:
- tail[0] = data[data_len - 1];
+ wl->tx_tail[0] = data[data_len - 1];
+ wl->tx_tail[1] = 0;
+ wl->tx_tail[2] = 0;
break;
}
b43_piotx_write32(q, B43_PIO8_TXCTL, ctl);
- ssb_block_write(dev->dev, tail, 4,
+ ssb_block_write(dev->dev, wl->tx_tail, 4,
q->mmio_base + B43_PIO8_TXDATA,
sizeof(u32));
}
@@ -445,8 +449,9 @@ static void pio_tx_frame_4byte_queue(struct b43_pio_txpacket *pack,
static int pio_tx_frame(struct b43_pio_txqueue *q,
struct sk_buff *skb)
{
+ struct b43_wldev *dev = q->dev;
+ struct b43_wl *wl = dev->wl;
struct b43_pio_txpacket *pack;
- struct b43_txhdr txhdr;
u16 cookie;
int err;
unsigned int hdrlen;
@@ -457,8 +462,8 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
struct b43_pio_txpacket, list);
cookie = generate_cookie(q, pack);
- hdrlen = b43_txhdr_size(q->dev);
- err = b43_generate_txhdr(q->dev, (u8 *)&txhdr, skb,
+ hdrlen = b43_txhdr_size(dev);
+ err = b43_generate_txhdr(dev, (u8 *)&wl->txhdr, skb,
info, cookie);
if (err)
return err;
@@ -466,15 +471,15 @@ static int pio_tx_frame(struct b43_pio_txqueue *q,
if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* Tell the firmware about the cookie of the last
* mcast frame, so it can clear the more-data bit in it. */
- b43_shm_write16(q->dev, B43_SHM_SHARED,
+ b43_shm_write16(dev, B43_SHM_SHARED,
B43_SHM_SH_MCASTCOOKIE, cookie);
}
pack->skb = skb;
if (q->rev >= 8)
- pio_tx_frame_4byte_queue(pack, (const u8 *)&txhdr, hdrlen);
+ pio_tx_frame_4byte_queue(pack, (const u8 *)&wl->txhdr, hdrlen);
else
- pio_tx_frame_2byte_queue(pack, (const u8 *)&txhdr, hdrlen);
+ pio_tx_frame_2byte_queue(pack, (const u8 *)&wl->txhdr, hdrlen);
/* Remove it from the list of available packet slots.
* It will be put back when we receive the status report. */
@@ -614,14 +619,14 @@ void b43_pio_get_tx_stats(struct b43_wldev *dev,
static bool pio_rx_frame(struct b43_pio_rxqueue *q)
{
struct b43_wldev *dev = q->dev;
- struct b43_rxhdr_fw4 rxhdr;
+ struct b43_wl *wl = dev->wl;
u16 len;
u32 macstat;
unsigned int i, padding;
struct sk_buff *skb;
const char *err_msg = NULL;
- memset(&rxhdr, 0, sizeof(rxhdr));
+ memset(&wl->rxhdr, 0, sizeof(wl->rxhdr));
/* Check if we have data and wait for it to get ready. */
if (q->rev >= 8) {
@@ -659,16 +664,16 @@ data_ready:
/* Get the preamble (RX header) */
if (q->rev >= 8) {
- ssb_block_read(dev->dev, &rxhdr, sizeof(rxhdr),
+ ssb_block_read(dev->dev, &wl->rxhdr, sizeof(wl->rxhdr),
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
} else {
- ssb_block_read(dev->dev, &rxhdr, sizeof(rxhdr),
+ ssb_block_read(dev->dev, &wl->rxhdr, sizeof(wl->rxhdr),
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
}
/* Sanity checks. */
- len = le16_to_cpu(rxhdr.frame_len);
+ len = le16_to_cpu(wl->rxhdr.frame_len);
if (unlikely(len > 0x700)) {
err_msg = "len > 0x700";
goto rx_error;
@@ -678,7 +683,7 @@ data_ready:
goto rx_error;
}
- macstat = le32_to_cpu(rxhdr.mac_status);
+ macstat = le32_to_cpu(wl->rxhdr.mac_status);
if (macstat & B43_RX_MAC_FCSERR) {
if (!(q->dev->wl->filter_flags & FIF_FCSFAIL)) {
/* Drop frames with failed FCS. */
@@ -703,24 +708,22 @@ data_ready:
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
if (len & 3) {
- u8 tail[4] = { 0, };
-
/* Read the last few bytes. */
- ssb_block_read(dev->dev, tail, 4,
+ ssb_block_read(dev->dev, wl->rx_tail, 4,
q->mmio_base + B43_PIO8_RXDATA,
sizeof(u32));
switch (len & 3) {
case 3:
- skb->data[len + padding - 3] = tail[0];
- skb->data[len + padding - 2] = tail[1];
- skb->data[len + padding - 1] = tail[2];
+ 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];
break;
case 2:
- skb->data[len + padding - 2] = tail[0];
- skb->data[len + padding - 1] = tail[1];
+ skb->data[len + padding - 2] = wl->rx_tail[0];
+ skb->data[len + padding - 1] = wl->rx_tail[1];
break;
case 1:
- skb->data[len + padding - 1] = tail[0];
+ skb->data[len + padding - 1] = wl->rx_tail[0];
break;
}
}
@@ -729,17 +732,15 @@ data_ready:
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
if (len & 1) {
- u8 tail[2] = { 0, };
-
/* Read the last byte. */
- ssb_block_read(dev->dev, tail, 2,
+ ssb_block_read(dev->dev, wl->rx_tail, 2,
q->mmio_base + B43_PIO_RXDATA,
sizeof(u16));
- skb->data[len + padding - 1] = tail[0];
+ skb->data[len + padding - 1] = wl->rx_tail[0];
}
}
- b43_rx(q->dev, skb, &rxhdr);
+ b43_rx(q->dev, skb, &wl->rxhdr);
return 1;
diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c
index ac9f600995e4..f4e9695ec186 100644
--- a/drivers/net/wireless/b43/xmit.c
+++ b/drivers/net/wireless/b43/xmit.c
@@ -27,7 +27,7 @@
*/
-#include "xmit.h"
+#include "b43.h"
#include "phy_common.h"
#include "dma.h"
#include "pio.h"
@@ -690,7 +690,10 @@ 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();
#if B43_DEBUG
dev->rx_count++;
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 1d9223b3d4c4..4b832e15856a 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -37,6 +37,7 @@
#include <linux/firmware.h>
#include <linux/wireless.h>
#include <linux/workqueue.h>
+#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/dma-mapping.h>
#include <net/dst.h>
@@ -3592,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;
@@ -3706,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/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c
index 11319ec2d64a..aaf227203a98 100644
--- a/drivers/net/wireless/b43legacy/phy.c
+++ b/drivers/net/wireless/b43legacy/phy.c
@@ -31,6 +31,7 @@
#include <linux/delay.h>
#include <linux/pci.h>
+#include <linux/sched.h>
#include <linux/types.h>
#include "b43legacy.h"
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_info.c b/drivers/net/wireless/hostap/hostap_info.c
index 6fa14a4e4b53..4dfb40a84c96 100644
--- a/drivers/net/wireless/hostap/hostap_info.c
+++ b/drivers/net/wireless/hostap/hostap_info.c
@@ -1,6 +1,7 @@
/* Host AP driver Info Frame processing (part of hostap.o module) */
#include <linux/if_arp.h>
+#include <linux/sched.h>
#include "hostap_wlan.h"
#include "hostap.h"
#include "hostap_ap.h"
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index 3f2bda881a4f..9419cebca8a5 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -1,6 +1,7 @@
/* ioctl() (mostly Linux Wireless Extensions) routines for Host AP driver */
#include <linux/types.h>
+#include <linux/sched.h>
#include <linux/ethtool.h>
#include <linux/if_arp.h>
#include <net/lib80211.h>
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 8d58e6ed4e7d..7f169e1eccf9 100644
--- a/drivers/net/wireless/ipw2x00/ipw2200.c
+++ b/drivers/net/wireless/ipw2x00/ipw2200.c
@@ -30,6 +30,7 @@
******************************************************************************/
+#include <linux/sched.h>
#include "ipw2200.h"
@@ -11275,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..a00f947bd59c 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 */
@@ -107,8 +111,7 @@ static struct iwl_lib_ops iwl1000_lib = {
.update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
.init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .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,8 +156,10 @@ 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,
@@ -161,5 +167,31 @@ struct iwl_cfg iwl1000_bgn_cfg = {
.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,
};
+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,
+ .need_pll_cfg = true,
+ .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,
+};
+
+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..ccdac69838dd 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
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-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
index a16bd4147eac..cbb0585083a9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c
@@ -702,7 +702,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
u8 sta_id = iwl_find_station(priv, hdr->addr1);
if (sta_id == IWL_INVALID_STATION) {
- IWL_DEBUG_RATE(priv, "LQ: ADD station %pm\n",
+ IWL_DEBUG_RATE(priv, "LQ: ADD station %pM\n",
hdr->addr1);
sta_id = iwl_add_station(priv, hdr->addr1, false,
CMD_ASYNC, NULL);
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index e70c5b0af364..afe19f2bd4f6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -30,6 +30,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
@@ -46,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, \
@@ -292,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);
@@ -352,16 +354,14 @@ 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;
+ iwl_leds_background(priv);
}
/******************************************************************************
@@ -544,14 +544,17 @@ 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;
/* 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;
}
@@ -563,24 +566,45 @@ 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
+ 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(hdr->frame_control) ||
+ ieee80211_has_protected(hdr->frame_control) ||
+ ieee80211_has_morefrags(hdr->frame_control) ||
+ 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;
+ }
+
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);
- rxb->skb = NULL;
+ 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)
@@ -590,7 +614,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);
@@ -610,7 +634,7 @@ static void iwl3945_rx_reply_rx(struct iwl_priv *priv,
if (rx_status.band == IEEE80211_BAND_5GHZ)
rx_status.rate_idx -= IWL_FIRST_OFDM_RATE;
- rx_status.antenna = le16_to_cpu(rx_hdr->phy_flags &
+ rx_status.antenna = (le16_to_cpu(rx_hdr->phy_flags) &
RX_RES_PHY_FLAGS_ANTENNA_MSK) >> 4;
/* set the preamble flag if appropriate */
@@ -790,29 +814,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)) {
@@ -830,22 +856,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)
@@ -961,6 +985,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)
@@ -985,37 +1014,66 @@ static int iwl3945_txq_ctx_reset(struct iwl_priv *priv)
return rc;
}
+/*
+ * Start up NIC's basic functionality after it has been reset
+ * (e.g. after platform boot, or shutdown via iwl3945_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);
+ /* Configure chip clock phase-lock-loop */
+ iwl_set_bit(priv, CSR_ANA_PLL_CFG, CSR39_ANA_PLL_CFG_VAL);
+ /*
+ * Disable L0S exit timer (platform NMI Work/Around)
+ * (does this do anything on 3945, or just 4965 and beyond?)
+ */
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) */
+ /* 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 */
+ /* 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);
+
+ /*
+ * 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);
- ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
- CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
+ /*
+ * 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 */
+ /* Enable DMA and BSM clocks, wait for them to stabilize */
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 */
+ /* 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);
+
+ /* 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);
+
+ /* Disable L1-Active */
iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
@@ -1144,12 +1202,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)
@@ -1170,85 +1232,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
@@ -1857,7 +1840,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,
@@ -1886,14 +1869,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;
}
@@ -2556,11 +2539,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;
@@ -2843,8 +2825,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,
},
@@ -2873,6 +2854,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 = {
@@ -2880,6 +2862,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 = {
@@ -2891,9 +2874,11 @@ 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,
.use_isr_legacy = true,
.ht_greenfield_support = false,
+ .led_compensation = 64,
};
static struct iwl_cfg iwl3945_abg_cfg = {
@@ -2905,9 +2890,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..f3907c1079f5 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
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 a22a0501c190..7e836e846d00 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -30,6 +30,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
@@ -44,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);
@@ -61,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 */
@@ -334,7 +334,8 @@ static int iwl4965_apm_init(struct iwl_priv *priv)
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,
+ 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");
@@ -395,79 +396,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. */
@@ -495,14 +423,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]) &&
@@ -556,18 +485,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,
@@ -662,7 +579,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 */
@@ -747,6 +665,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)
@@ -763,19 +685,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;
@@ -1804,11 +1723,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;
}
@@ -1869,11 +1790,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;
}
@@ -2077,7 +2000,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);
@@ -2278,7 +2201,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,
};
@@ -2302,8 +2225,7 @@ static struct iwl_lib_ops iwl4965_lib = {
.dump_nic_error_log = iwl_dump_nic_error_log,
.apm_ops = {
.init = iwl4965_apm_init,
- .reset = iwl4965_apm_reset,
- .stop = iwl4965_apm_stop,
+ .stop = iwl_apm_stop,
.config = iwl4965_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -2339,6 +2261,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 = {
@@ -2351,30 +2274,35 @@ 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,
.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 eb08f4411000..955116542717 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -29,6 +29,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
@@ -42,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"
@@ -71,26 +73,6 @@ 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;
@@ -117,7 +99,8 @@ int iwl5000_apm_init(struct iwl_priv *priv)
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,
+ 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");
@@ -136,69 +119,7 @@ int iwl5000_apm_init(struct iwl_priv *priv)
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;
@@ -221,7 +142,7 @@ void iwl5000_nic_config(struct iwl_priv *priv)
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) |
@@ -301,14 +222,17 @@ 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;
@@ -317,7 +241,7 @@ static void iwl5000_gain_computation(struct iwl_priv *priv,
(s32)average_noise[i])) / 1500;
/* bound gain by 2 bits value max, 3rd bit is sign */
data->delta_gain_code[i] =
- min(abs(delta_g), CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
+ min(abs(delta_g), (long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
if (delta_g < 0)
/* set negative sign */
@@ -406,6 +330,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 = {
@@ -428,6 +356,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,
@@ -492,7 +424,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;
@@ -745,7 +677,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,
@@ -817,32 +750,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) |
@@ -988,11 +911,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;
}
@@ -1046,11 +971,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;
}
@@ -1217,7 +1144,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);
@@ -1458,6 +1385,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) \
@@ -1500,6 +1445,7 @@ 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 = {
@@ -1544,8 +1490,7 @@ struct iwl_lib_ops iwl5000_lib = {
.update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
.init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .stop = iwl_apm_stop,
.config = iwl5000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -1596,8 +1541,7 @@ static struct iwl_lib_ops iwl5150_lib = {
.update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
.init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .stop = iwl_apm_stop,
.config = iwl5000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -1626,11 +1570,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 = {
@@ -1638,11 +1583,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 */
@@ -1659,11 +1603,15 @@ 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,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5100_bg_cfg = {
@@ -1676,11 +1624,15 @@ 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,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5100_abg_cfg = {
@@ -1693,11 +1645,15 @@ 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,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5100_agn_cfg = {
@@ -1710,11 +1666,15 @@ 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,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5350_agn_cfg = {
@@ -1727,11 +1687,15 @@ 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,
.ht_greenfield_support = true,
+ .led_compensation = 51,
+ .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
};
struct iwl_cfg iwl5150_agn_cfg = {
@@ -1744,24 +1708,29 @@ 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,
.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..bdc1c74b6820 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -44,6 +44,8 @@
#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
@@ -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,78 @@ 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 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,
@@ -108,8 +194,7 @@ static struct iwl_lib_ops iwl6000_lib = {
.update_chain_flags = iwl_update_chain_flags,
.apm_ops = {
.init = iwl5000_apm_init,
- .reset = iwl5000_apm_reset,
- .stop = iwl5000_apm_stop,
+ .stop = iwl_apm_stop,
.config = iwl6000_nic_config,
.set_pwr_src = iwl_set_pwr_src,
},
@@ -139,18 +224,12 @@ static struct iwl_lib_ops iwl6000_lib = {
},
};
-static struct iwl_hcmd_utils_ops iwl6000_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 = {
.ucode = &iwl5000_ucode,
.lib = &iwl6000_lib,
.hcmd = &iwl5000_hcmd,
- .utils = &iwl6000_hcmd_utils,
+ .utils = &iwl5000_hcmd_utils,
+ .led = &iwlagn_led_ops,
};
@@ -165,8 +244,61 @@ 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,
+ .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,
+};
+
+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,
+ .need_pll_cfg = 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,
+};
+
+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,
@@ -175,6 +307,9 @@ struct iwl_cfg iwl6000h_2agn_cfg = {
.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,
};
/*
@@ -188,8 +323,61 @@ 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,
+ .need_pll_cfg = 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,
+};
+
+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,
+ .need_pll_cfg = 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,
+};
+
+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,
@@ -198,6 +386,9 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
.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,
};
struct iwl_cfg iwl6050_2agn_cfg = {
@@ -208,8 +399,36 @@ struct iwl_cfg iwl6050_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,
+ .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,
+};
+
+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 = &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,
@@ -218,6 +437,9 @@ struct iwl_cfg iwl6050_2agn_cfg = {
.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,
};
struct iwl_cfg iwl6000_3agn_cfg = {
@@ -228,8 +450,10 @@ 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,
@@ -238,6 +462,10 @@ struct iwl_cfg iwl6000_3agn_cfg = {
.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,
};
struct iwl_cfg iwl6050_3agn_cfg = {
@@ -248,8 +476,10 @@ struct iwl_cfg iwl6050_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,
@@ -258,6 +488,10 @@ struct iwl_cfg iwl6050_3agn_cfg = {
.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,
};
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..a07be29cc5e5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -171,6 +171,8 @@ struct iwl_lq_sta {
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 void rs_rate_scale_perform(struct iwl_priv *priv,
@@ -190,84 +192,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_legacy[IWL_RATE_COUNT] = {
+ 7, 13, 35, 58, 40, 57, 72, 98, 121, 154, 177, 186, 0
};
-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_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_siso40MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 77, 77, 127, 160, 184, 220, 242, 250, 257
+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 */
};
-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_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_mimo2_40MHz[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 123, 123, 182, 214, 235, 264, 279, 285, 289
+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_mimo2_40MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 131, 131, 191, 222, 242, 270, 284, 289, 293
+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 */
};
-/* 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_mimo3_20MHzSGI[IWL_RATE_COUNT] = {
- 0, 0, 0, 0, 106, 106, 162, 194, 215, 246, 262, 268, 273
-};
-
-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_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 +414,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 +440,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 +450,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 +461,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 +476,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 +667,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 +817,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 +864,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 +881,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 +900,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 +910,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 +1047,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 +2060,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 +2168,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));
@@ -2681,6 +2681,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 +2800,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);
@@ -2933,8 +2934,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.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index cdc07c477457..401295cf20fb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -33,6 +33,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
@@ -115,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) {
@@ -217,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,
*/
@@ -520,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;
@@ -606,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);
@@ -630,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;
@@ -782,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.
@@ -818,10 +826,10 @@ void iwl_rx_handle(struct iwl_priv *priv)
}
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 && rxb->page)
iwl_tx_cmd_complete(priv, rxb);
else
IWL_WARN(priv, "Claim null rxb?\n");
@@ -830,10 +838,10 @@ void iwl_rx_handle(struct iwl_priv *priv)
/* 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;
+ if (rxb->page != NULL) {
+ priv->alloc_rxb_page--;
+ __free_pages(rxb->page, priv->hw_params.rx_page_order);
+ rxb->page = NULL;
}
spin_lock_irqsave(&rxq->lock, flags);
@@ -900,6 +908,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
@@ -921,8 +931,6 @@ static void iwl_irq_tasklet_legacy(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR;
- spin_unlock_irqrestore(&priv->lock, flags);
-
return;
}
@@ -1049,7 +1057,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 */
@@ -1079,6 +1086,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;
@@ -1094,8 +1104,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR;
- spin_unlock_irqrestore(&priv->lock, flags);
-
return;
}
@@ -1235,14 +1243,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);
-
}
@@ -1606,6 +1610,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",
@@ -1654,12 +1661,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);
}
}
}
@@ -1758,6 +1767,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;
@@ -1785,7 +1798,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);
@@ -1823,8 +1836,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 */
@@ -1885,11 +1896,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));
@@ -2323,6 +2332,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");
@@ -2794,6 +2805,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);
+
/*****************************************************************************
*
@@ -2850,6 +2895,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
@@ -3105,8 +3151,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
out_pci_disable_device:
pci_disable_device(pdev);
out_ieee80211_free_hw:
- ieee80211_free_hw(priv->hw);
iwl_free_traffic_mem(priv);
+ ieee80211_free_hw(priv->hw);
out:
return err;
}
@@ -3215,20 +3261,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}
@@ -3283,9 +3360,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 2c5c88fc38f5..7d4f131708f3 100644
--- a/drivers/net/wireless/iwlwifi/iwl-commands.h
+++ b/drivers/net/wireless/iwlwifi/iwl-commands.h
@@ -148,7 +148,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 +353,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 +414,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 +806,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 +816,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)
*/
@@ -1154,7 +1209,7 @@ struct iwl_wep_cmd {
#define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1)
#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2)
#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3)
-#define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0)
+#define RX_RES_PHY_FLAGS_ANTENNA_MSK 0xf0
#define RX_RES_PHY_FLAGS_ANTENNA_POS 4
#define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8)
@@ -3237,12 +3292,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 +3544,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 484d5c1a7312..ad6267330267 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -29,6 +29,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/etherdevice.h>
+#include <linux/sched.h>
#include <net/mac80211.h>
#include "iwl-eeprom.h"
@@ -604,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,
@@ -634,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
@@ -653,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);
@@ -877,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 |
@@ -892,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 */
@@ -901,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;
@@ -914,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;
@@ -937,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);
@@ -954,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 */
@@ -1004,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;
}
@@ -1280,7 +1282,7 @@ 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",
@@ -1345,6 +1347,42 @@ 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_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);
+
void iwl_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
@@ -1455,10 +1493,9 @@ 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;
@@ -1487,15 +1524,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);
@@ -2142,7 +2176,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);
@@ -2153,7 +2187,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,
@@ -2165,7 +2199,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",
@@ -2227,42 +2261,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");
}
@@ -2386,6 +2436,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.
@@ -2396,9 +2448,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) {
@@ -2569,7 +2622,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;
@@ -2619,21 +2672,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;
@@ -2655,7 +2705,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");
@@ -2739,7 +2790,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);
@@ -2791,6 +2842,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..b877f8893fdf 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);
@@ -185,18 +186,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 +220,11 @@ 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
*
* 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,6 +256,8 @@ 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;
@@ -254,7 +268,11 @@ struct iwl_cfg {
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;
};
/***************************
@@ -273,7 +291,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);
@@ -309,6 +327,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 +531,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 +591,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 +636,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 +662,8 @@ 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);
void iwl_setup_rxon_timing(struct iwl_priv *priv);
static inline int iwl_send_rxon_assoc(struct iwl_priv *priv)
@@ -653,5 +683,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..8f183e0fa512 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -230,13 +230,18 @@
/* 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 */
+/* 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..b9ca475cc61c 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;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index a198bcf61022..2cd11ba96370 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,7 +801,9 @@ 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))
@@ -861,9 +866,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 +884,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 +983,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 +1079,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 +1111,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 +1388,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 +1414,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 +1530,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 +1560,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;
@@ -1661,9 +1849,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);
@@ -1716,9 +1902,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);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 028d50599550..35d579455c3c 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;
@@ -82,8 +86,6 @@ extern void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info,
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 +146,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 +168,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 +324,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 {
@@ -358,6 +367,13 @@ enum {
#define IWL_CMD_MAX_PAYLOAD 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
*
@@ -382,10 +398,10 @@ 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;
@@ -502,12 +518,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;
@@ -622,6 +637,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 +658,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 +681,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;
@@ -726,9 +744,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 +756,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 +861,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 +981,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 +994,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 +1081,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 +1095,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 +1107,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 +1130,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 3d2b93a61e62..2e8c40576d22 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)
@@ -345,7 +370,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) {
@@ -410,7 +436,6 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
u16 *validblockaddr)
{
u16 next_link_addr = 0, link_value = 0, valid_addr;
- int ret = 0;
int usedblocks = 0;
/* set addressing mode to absolute to traverse the link list */
@@ -430,29 +455,29 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
* check for more block on the link list
*/
valid_addr = next_link_addr;
- next_link_addr = link_value;
+ next_link_addr = link_value * sizeof(u16);
IWL_DEBUG_INFO(priv, "OTP blocks %d addr 0x%x\n",
usedblocks, next_link_addr);
if (iwl_read_otp_word(priv, next_link_addr, &link_value))
return -EINVAL;
if (!link_value) {
/*
- * reach the end of link list,
+ * reach the end of link list, return success and
* set address point to the starting address
* of the image
*/
- goto done;
+ *validblockaddr = valid_addr;
+ /* skip first 2 bytes (link list pointer) */
+ *validblockaddr += 2;
+ return 0;
}
/* more in the link list, continue */
usedblocks++;
- } while (usedblocks < priv->cfg->max_ll_items);
- /* OTP full, use last block */
- IWL_DEBUG_INFO(priv, "OTP is full, use last block\n");
-done:
- *validblockaddr = valid_addr;
- /* skip first 2 bytes (link list pointer) */
- *validblockaddr += 2;
- return ret;
+ } while (usedblocks <= priv->cfg->max_ll_items);
+
+ /* OTP has no valid blocks */
+ IWL_DEBUG_INFO(priv, "OTP has no valid blocks\n");
+ return -EINVAL;
}
/**
@@ -538,7 +563,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 6b68db7b1b81..b363c96fd6c6 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;
/*
@@ -220,35 +222,35 @@ struct iwl_eeprom_enhanced_txpwr {
* Section 10: 2.4 GHz 40MHz channels: 132, 44 (_above_)
*/
/* 2.4 GHz band: CCK */
-#define EEPROM_LB_CCK_20_COMMON ((0xAA)\
+#define EEPROM_LB_CCK_20_COMMON ((0xA8)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 8 bytes */
/* 2.4 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */
-#define EEPROM_LB_OFDM_COMMON ((0xB2)\
+#define EEPROM_LB_OFDM_COMMON ((0xB0)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
/* 5.2 GHz band: 20MHz-Legacy, 20MHz-HT, 40MHz-HT */
-#define EEPROM_HB_OFDM_COMMON ((0xCA)\
+#define EEPROM_HB_OFDM_COMMON ((0xC8)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
/* 2.4GHz band channels:
* 1Legacy, 1HT, 2Legacy, 2HT, 10Legacy, 10HT, 11Legacy, 11HT */
-#define EEPROM_LB_OFDM_20_BAND ((0xE2)\
+#define EEPROM_LB_OFDM_20_BAND ((0xE0)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 64 bytes */
/* 2.4 GHz band HT40 channels: (1,+1) (2,+1) (6,+1) (7,+1) (9,+1) */
-#define EEPROM_LB_OFDM_HT40_BAND ((0x122)\
+#define EEPROM_LB_OFDM_HT40_BAND ((0x120)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 40 bytes */
/* 5.2GHz band channels: 36Legacy, 36HT, 64Legacy, 64HT, 100Legacy, 100HT */
-#define EEPROM_HB_OFDM_20_BAND ((0x14A)\
+#define EEPROM_HB_OFDM_20_BAND ((0x148)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 48 bytes */
/* 5.2 GHz band HT40 channels: (36,+1) (60,+1) (100,+1) */
-#define EEPROM_HB_OFDM_HT40_BAND ((0x17A)\
+#define EEPROM_HB_OFDM_HT40_BAND ((0x178)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 24 bytes */
/* 2.4 GHz band, channnel 13: Legacy, HT */
-#define EEPROM_LB_OFDM_20_CHANNEL_13 ((0x192)\
+#define EEPROM_LB_OFDM_20_CHANNEL_13 ((0x190)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
/* 5.2 GHz band, channnel 140: Legacy, HT */
-#define EEPROM_HB_OFDM_20_CHANNEL_140 ((0x1A2)\
+#define EEPROM_HB_OFDM_20_CHANNEL_140 ((0x1A0)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
/* 5.2 GHz band, HT40 channnels (132,+1) (44,+1) */
-#define EEPROM_HB_OFDM_HT40_BAND_1 ((0x1B2)\
+#define EEPROM_HB_OFDM_HT40_BAND_1 ((0x1B0)\
| INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 16 bytes */
@@ -256,6 +258,12 @@ 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)
+
+/* 60x0 Specific */
+#define EEPROM_6000_EEPROM_VERSION (0x434)
+
/* OTP */
/* lower blocks contain EEPROM image and calibration data */
#define OTP_LOW_IMAGE_SIZE (2 * 512 * sizeof(u16)) /* 2 KB */
@@ -370,12 +378,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 +393,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 532c8d6cd8da..1bf17d21051d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c
@@ -28,6 +28,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/sched.h>
#include <net/mac80211.h>
#include "iwl-dev.h" /* FIXME: remove */
@@ -103,17 +104,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);
@@ -215,7 +207,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;
@@ -237,9 +229,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);
@@ -272,7 +264,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..9c6b14952061 100644
--- a/drivers/net/wireless/iwlwifi/iwl-power.c
+++ b/drivers/net/wireless/iwlwifi/iwl-power.c
@@ -165,26 +165,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 +294,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 +351,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 +392,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 +430,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 +454,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 +494,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 +523,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 +545,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 +593,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 +644,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 +677,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 +695,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 +740,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 +771,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 +818,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,8 +851,12 @@ 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);
@@ -826,6 +913,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 8e1bb53c0aa3..0a407f79de01 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,7 +239,7 @@ 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;
while (1) {
@@ -252,29 +252,34 @@ void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
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);
- if (!skb) {
+ if (priv->hw_params.rx_page_order > 0)
+ priority |= __GFP_COMP;
+
+ /* Alloc a new receive buffer */
+ page = alloc_pages(priority, 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 +288,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 +338,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 +409,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 +495,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 +552,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 +608,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);
@@ -878,6 +923,9 @@ 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;
+
/* We only process data packets if the interface is open */
if (unlikely(!priv->is_open)) {
IWL_DEBUG_DROP_LIMIT(priv,
@@ -890,15 +938,38 @@ 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(hdr->frame_control) ||
+ ieee80211_has_protected(hdr->frame_control) ||
+ ieee80211_has_morefrags(hdr->frame_control) ||
+ 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;
+ }
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;
+ memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats));
+
+ 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 +997,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;
@@ -1044,7 +1115,7 @@ void iwl_rx_reply_rx(struct iwl_priv *priv,
* as a bitmask.
*/
rx_status.antenna =
- le16_to_cpu(phy_res->phy_flags & RX_RES_PHY_FLAGS_ANTENNA_MSK)
+ (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK)
>> RX_RES_PHY_FLAGS_ANTENNA_POS;
/* set the preamble flag if appropriate */
@@ -1087,7 +1158,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 c18907544701..0bda1967f210 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -28,6 +28,7 @@
*****************************************************************************/
#include <linux/etherdevice.h>
+#include <linux/sched.h>
#include <net/mac80211.h>
#include "iwl-eeprom.h"
#include "iwl-dev.h"
@@ -405,15 +406,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);
@@ -445,6 +450,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 */
@@ -581,9 +592,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;
@@ -709,7 +718,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;
@@ -842,7 +851,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;
@@ -876,7 +885,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);
@@ -910,6 +919,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);
@@ -969,13 +984,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;
}
@@ -1038,6 +1059,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));
@@ -1131,7 +1154,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);
@@ -1158,10 +1181,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);
@@ -1400,7 +1423,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;
@@ -1420,7 +1443,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 c390dbd877e4..5f3b6ea71481 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -33,6 +33,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
@@ -41,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>
@@ -89,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 */
@@ -367,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;
@@ -381,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);
@@ -407,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))
@@ -425,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;
@@ -451,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;
}
/*
@@ -473,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;
@@ -572,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.
@@ -587,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)
@@ -601,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;
@@ -619,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));
/*
@@ -757,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,
@@ -802,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;
@@ -825,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;
}
@@ -834,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;
@@ -871,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);
@@ -907,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;
@@ -930,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;
@@ -1094,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--;
@@ -1134,7 +1123,7 @@ 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;
while (1) {
@@ -1148,9 +1137,13 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv, gfp_t priority)
if (rxq->free_count > RX_LOW_WATERMARK)
priority |= __GFP_NOWARN;
+
+ if (priv->hw_params.rx_page_order > 0)
+ priority |= __GFP_COMP;
+
/* Alloc a new receive buffer */
- skb = alloc_skb(priv->hw_params.rx_buf_size, priority);
- if (!skb) {
+ page = alloc_pages(priority, 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) &&
@@ -1167,7 +1160,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;
@@ -1175,26 +1168,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);
}
}
@@ -1210,14 +1195,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);
}
@@ -1225,8 +1210,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);
}
@@ -1259,12 +1244,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--;
}
}
@@ -1400,10 +1387,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.
@@ -1425,16 +1415,17 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
priv->isr_stats.rx_handlers[pkt->hdr.cmd]++;
} 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);
}
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 && rxb->page)
iwl_tx_cmd_complete(priv, rxb);
else
IWL_WARN(priv, "Claim null rxb?\n");
@@ -1443,10 +1434,10 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
/* 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;
+ if (rxb->page != NULL) {
+ priv->alloc_rxb_page--;
+ __free_pages(rxb->page, priv->hw_params.rx_page_order);
+ rxb->page = NULL;
}
spin_lock_irqsave(&rxq->lock, flags);
@@ -1550,8 +1541,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))
@@ -1591,10 +1583,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);
}
}
}
@@ -1684,6 +1678,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
@@ -1705,8 +1701,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
handled |= CSR_INT_BIT_HW_ERR;
- spin_unlock_irqrestore(&priv->lock, flags);
-
return;
}
@@ -1798,7 +1792,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,
@@ -2478,7 +2471,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);
@@ -2516,7 +2509,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 */
@@ -2562,11 +2554,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);
@@ -2575,10 +2562,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));
@@ -2723,19 +2708,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));
@@ -3151,6 +3151,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;
@@ -3794,7 +3796,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;
@@ -4053,6 +4054,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
@@ -4096,8 +4098,8 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
pci_set_drvdata(pdev, NULL);
pci_disable_device(pdev);
out_ieee80211_free_hw:
- ieee80211_free_hw(priv->hw);
iwl_free_traffic_mem(priv);
+ ieee80211_free_hw(priv->hw);
out:
return err;
}
@@ -4225,18 +4227,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/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
index a56a2b0ac99a..f3c55658225b 100644
--- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c
+++ b/drivers/net/wireless/iwmc3200wifi/cfg80211.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/sched.h>
#include <linux/etherdevice.h>
#include <linux/wireless.h>
#include <linux/ieee80211.h>
diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c
index 23b52fa2605f..84158b6d35d8 100644
--- a/drivers/net/wireless/iwmc3200wifi/commands.c
+++ b/drivers/net/wireless/iwmc3200wifi/commands.c
@@ -40,6 +40,7 @@
#include <linux/wireless.h>
#include <linux/etherdevice.h>
#include <linux/ieee80211.h>
+#include <linux/sched.h>
#include "iwm.h"
#include "bus.h"
diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c
index d668e4756324..68fb3dc775b7 100644
--- a/drivers/net/wireless/iwmc3200wifi/main.c
+++ b/drivers/net/wireless/iwmc3200wifi/main.c
@@ -38,6 +38,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/sched.h>
#include <linux/ieee80211.h>
#include <linux/wireless.h>
@@ -637,6 +638,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);
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 40dbcbc16593..771a301003c9 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -38,6 +38,7 @@
#include <linux/kernel.h>
#include <linux/netdevice.h>
+#include <linux/sched.h>
#include <linux/etherdevice.h>
#include <linux/wireless.h>
#include <linux/ieee80211.h>
diff --git a/drivers/net/wireless/libertas/Kconfig b/drivers/net/wireless/libertas/Kconfig
new file mode 100644
index 000000000000..8f8d75b61ea9
--- /dev/null
+++ b/drivers/net/wireless/libertas/Kconfig
@@ -0,0 +1,39 @@
+config LIBERTAS
+ tristate "Marvell 8xxx Libertas WLAN driver support"
+ depends on WLAN_80211 && 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..e5584dd1c79a 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,5 +1,16 @@
-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 += 11d.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/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 685098148e10..30622e6dee14 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -6,6 +6,7 @@
#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"
@@ -17,7 +18,6 @@
static struct cmd_ctrl_node *lbs_get_cmd_ctrl_node(struct lbs_private *priv);
-
/**
* @brief Simple callback that copies response back into command
*
@@ -76,6 +76,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
@@ -319,6 +343,60 @@ int lbs_cmd_802_11_sleep_params(struct lbs_private *priv, uint16_t cmd_action,
return 0;
}
+static int lbs_wait_for_ds_awake(struct lbs_private *priv)
+{
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ 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;
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep)
+{
+ int ret = 0;
+
+ lbs_deb_enter(LBS_DEB_CMD);
+
+ 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");
+ }
+ } 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");
+ }
+ }
+ }
+
+ lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
+ return ret;
+}
+
int lbs_cmd_802_11_set_wep(struct lbs_private *priv, uint16_t cmd_action,
struct assoc_request *assoc)
{
@@ -1242,8 +1320,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);
}
@@ -1390,6 +1477,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) {
@@ -1505,6 +1597,10 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
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(S_DS_GEN);
+ break;
default:
lbs_pr_err("PREP_CMD: unknown command 0x%04x\n", cmd_no);
ret = -1;
@@ -2023,7 +2119,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)
@@ -2038,6 +2134,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");
diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h
index 392e578ca095..2730c6aadfd2 100644
--- a/drivers/net/wireless/libertas/cmd.h
+++ b/drivers/net/wireless/libertas/cmd.h
@@ -26,6 +26,11 @@ int __lbs_cmd(struct lbs_private *priv, uint16_t command,
int (*callback)(struct lbs_private *, unsigned long, struct cmd_header *),
unsigned long callback_arg);
+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_power_adapt_cfg(struct lbs_private *priv, int enable, int8_t p0,
int8_t p1, int8_t p2);
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index c42d3faa2660..9ee8bd11bda9 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -3,6 +3,7 @@
* responses as well as events generated by firmware.
*/
#include <linux/delay.h>
+#include <linux/sched.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
#include <asm/unaligned.h>
@@ -504,9 +505,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 */
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..fb91c3639fc1 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -33,6 +33,9 @@ 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);
+int lbs_set_deep_sleep(struct lbs_private *priv, int deep_sleep);
+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);
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 72f3479a4d70..1cf5d5985dac 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)
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h
index d3b69a4b4b5e..8abb28af5afa 100644
--- a/drivers/net/wireless/libertas/dev.h
+++ b/drivers/net/wireless/libertas/dev.h
@@ -100,6 +100,7 @@ struct lbs_mesh_stats {
/** Private structure for the MV device */
struct lbs_private {
+ struct wireless_dev *wdev;
int mesh_open;
int mesh_fw_ver;
int infra_open;
@@ -129,6 +130,20 @@ struct lbs_private {
u32 bbp_offset;
u32 rf_offset;
+ /** Deep sleep flag */
+ int is_deep_sleep;
+ /** Auto deep sleep enabled flag */
+ int is_auto_deep_sleep_enabled;
+ /** Device wakeup required flag */
+ int wakeup_dev_required;
+ /** Auto deep sleep flag*/
+ int is_activity_detected;
+ /** Auto deep sleep timeout (in miliseconds) */
+ int auto_deep_sleep_timeout;
+
+ /** Deep sleep wait queue */
+ wait_queue_head_t ds_awake_q;
+
/* Download sent:
bit0 1/0=data_sent/data_tx_done,
bit1 1/0=cmd_sent/cmd_tx_done,
@@ -154,6 +169,9 @@ struct lbs_private {
/** Hardware access */
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;
@@ -204,6 +222,7 @@ struct lbs_private {
/** Timers */
struct timer_list command_timer;
+ struct timer_list auto_deepsleep_timer;
int nr_retries;
int cmd_timed_out;
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h
index fe8f0cb737bc..c055daabea13 100644
--- a/drivers/net/wireless/libertas/host.h
+++ b/drivers/net/wireless/libertas/host.h
@@ -57,6 +57,7 @@
#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
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 62381768f2d5..465742f19ecb 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -946,6 +946,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..06df2e174b50 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -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..b7363236cc53 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"
@@ -574,8 +576,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 +774,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 +827,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 +874,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 +908,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 +945,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 +1068,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,
@@ -1099,11 +1173,17 @@ static int lbs_init_adapter(struct lbs_private *priv)
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 +1222,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 +1249,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 +1292,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 +1309,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 +1326,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:
@@ -1272,11 +1376,17 @@ void lbs_remove_card(struct lbs_private *priv)
wrqu.ap_addr.sa_family = ARPHRD_ETHER;
wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL);
+ 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);
@@ -1301,8 +1411,8 @@ int lbs_start_card(struct lbs_private *priv)
/* 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;
}
@@ -1392,6 +1502,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);
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index 6c95af3023cc..d8fc2b8b3027 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -1022,9 +1022,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 +1061,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;
}
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c
index 4c018f7a0a8d..8c3766a6e8e7 100644
--- a/drivers/net/wireless/libertas/tx.c
+++ b/drivers/net/wireless/libertas/tx.c
@@ -3,6 +3,7 @@
*/
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/sched.h>
#include "hostcmd.h"
#include "radiotap.h"
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c
index be837a0d2517..4594841cd4af 100644
--- a/drivers/net/wireless/libertas/wext.c
+++ b/drivers/net/wireless/libertas/wext.c
@@ -45,7 +45,6 @@ static inline void lbs_cancel_association_work(struct lbs_private *priv)
priv->pending_assoc_req = NULL;
}
-
/**
* @brief Find the channel frequency power info with specific channel
*
@@ -709,6 +708,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 +737,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 +798,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 +832,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 +881,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 +911,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;
@@ -1000,6 +1051,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);
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/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/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index 4c97c6ad6f5d..bc08464d8323 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -19,6 +19,7 @@
*
*/
+#include <linux/capability.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/if_arp.h>
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index e26d7b3ceab5..2505be56ae39 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -23,6 +23,7 @@
#include <linux/netdevice.h>
#include <linux/ethtool.h>
#include <linux/pci.h>
+#include <linux/sched.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
#include <linux/if_arp.h>
diff --git a/drivers/net/wireless/prism54/islpci_mgt.c b/drivers/net/wireless/prism54/islpci_mgt.c
index f7c677e2094d..69d2f882fd06 100644
--- a/drivers/net/wireless/prism54/islpci_mgt.c
+++ b/drivers/net/wireless/prism54/islpci_mgt.c
@@ -20,6 +20,7 @@
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/sched.h>
#include <asm/io.h>
#include <asm/system.h>
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index a084077a1c61..9fe770f7d7bb 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -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/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c
index 7b3ee8c2eaef..68bc9bb1dbf9 100644
--- a/drivers/net/wireless/rt2x00/rt2x00debug.c
+++ b/drivers/net/wireless/rt2x00/rt2x00debug.c
@@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/poll.h>
+#include <linux/sched.h>
#include <linux/uaccess.h>
#include "rt2x00.h"
diff --git a/drivers/net/wireless/wl12xx/wl1251_main.c b/drivers/net/wireless/wl12xx/wl1251_main.c
index 1103256ad989..ec01e9dadb0d 100644
--- a/drivers/net/wireless/wl12xx/wl1251_main.c
+++ b/drivers/net/wireless/wl12xx/wl1251_main.c
@@ -185,6 +185,9 @@ static int wl1251_chip_wakeup(struct wl1251 *wl)
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;
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_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..dbf07bea87c0 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;
@@ -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/znet.c b/drivers/net/znet.c
index a0384b6f09b6..b42347333750 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -169,7 +169,6 @@ static void znet_tx_timeout (struct net_device *dev);
static int znet_request_resources (struct net_device *dev)
{
struct znet_private *znet = netdev_priv(dev);
- unsigned long flags;
if (request_irq (dev->irq, &znet_interrupt, 0, "ZNet", dev))
goto failed;
@@ -187,13 +186,9 @@ static int znet_request_resources (struct net_device *dev)
free_sia:
release_region (znet->sia_base, znet->sia_size);
free_tx_dma:
- flags = claim_dma_lock();
free_dma (znet->tx_dma);
- release_dma_lock (flags);
free_rx_dma:
- flags = claim_dma_lock();
free_dma (znet->rx_dma);
- release_dma_lock (flags);
free_irq:
free_irq (dev->irq, dev);
failed:
@@ -203,14 +198,11 @@ static int znet_request_resources (struct net_device *dev)
static void znet_release_resources (struct net_device *dev)
{
struct znet_private *znet = netdev_priv(dev);
- unsigned long flags;
release_region (znet->sia_base, znet->sia_size);
release_region (dev->base_addr, znet->io_size);
- flags = claim_dma_lock();
free_dma (znet->tx_dma);
free_dma (znet->rx_dma);
- release_dma_lock (flags);
free_irq (dev->irq, dev);
}
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
index 2b7ae366ceb1..5df60a6b6776 100644
--- a/drivers/oprofile/event_buffer.c
+++ b/drivers/oprofile/event_buffer.c
@@ -35,12 +35,23 @@ static size_t buffer_pos;
/* atomic_t because wait_event checks it outside of buffer_mutex */
static atomic_t buffer_ready = ATOMIC_INIT(0);
-/* Add an entry to the event buffer. When we
- * get near to the end we wake up the process
- * sleeping on the read() of the file.
+/*
+ * Add an entry to the event buffer. When we get near to the end we
+ * wake up the process sleeping on the read() of the file. To protect
+ * the event_buffer this function may only be called when buffer_mutex
+ * is set.
*/
void add_event_entry(unsigned long value)
{
+ /*
+ * This shouldn't happen since all workqueues or handlers are
+ * canceled or flushed before the event buffer is freed.
+ */
+ if (!event_buffer) {
+ WARN_ON_ONCE(1);
+ return;
+ }
+
if (buffer_pos == buffer_size) {
atomic_inc(&oprofile_stats.event_lost_overflow);
return;
@@ -69,7 +80,6 @@ void wake_up_buffer_waiter(void)
int alloc_event_buffer(void)
{
- int err = -ENOMEM;
unsigned long flags;
spin_lock_irqsave(&oprofilefs_lock, flags);
@@ -80,21 +90,22 @@ int alloc_event_buffer(void)
if (buffer_watershed >= buffer_size)
return -EINVAL;
+ buffer_pos = 0;
event_buffer = vmalloc(sizeof(unsigned long) * buffer_size);
if (!event_buffer)
- goto out;
+ return -ENOMEM;
- err = 0;
-out:
- return err;
+ return 0;
}
void free_event_buffer(void)
{
+ mutex_lock(&buffer_mutex);
vfree(event_buffer);
-
+ buffer_pos = 0;
event_buffer = NULL;
+ mutex_unlock(&buffer_mutex);
}
@@ -167,6 +178,12 @@ static ssize_t event_buffer_read(struct file *file, char __user *buf,
mutex_lock(&buffer_mutex);
+ /* May happen if the buffer is freed during pending reads. */
+ if (!event_buffer) {
+ retval = -EINTR;
+ goto out;
+ }
+
atomic_set(&buffer_ready, 0);
retval = -EFAULT;
diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c
index 14bbaa17e2ca..22b02c6df854 100644
--- a/drivers/pci/dmar.c
+++ b/drivers/pci/dmar.c
@@ -354,6 +354,7 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
struct acpi_dmar_hardware_unit *drhd;
struct acpi_dmar_reserved_memory *rmrr;
struct acpi_dmar_atsr *atsr;
+ struct acpi_dmar_rhsa *rhsa;
switch (header->type) {
case ACPI_DMAR_TYPE_HARDWARE_UNIT:
@@ -375,6 +376,12 @@ dmar_table_print_dmar_entry(struct acpi_dmar_header *header)
atsr = container_of(header, struct acpi_dmar_atsr, header);
printk(KERN_INFO PREFIX "ATSR flags: %#x\n", atsr->flags);
break;
+ case ACPI_DMAR_HARDWARE_AFFINITY:
+ rhsa = container_of(header, struct acpi_dmar_rhsa, header);
+ printk(KERN_INFO PREFIX "RHSA base: %#016Lx proximity domain: %#x\n",
+ (unsigned long long)rhsa->base_address,
+ rhsa->proximity_domain);
+ break;
}
}
@@ -459,9 +466,13 @@ parse_dmar_table(void)
ret = dmar_parse_one_atsr(entry_header);
#endif
break;
+ case ACPI_DMAR_HARDWARE_AFFINITY:
+ /* We don't do anything with RHSA (yet?) */
+ break;
default:
printk(KERN_WARNING PREFIX
- "Unknown DMAR structure type\n");
+ "Unknown DMAR structure type %d\n",
+ entry_header->type);
ret = 0; /* for forward compatibility */
break;
}
diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h
index 53836001d511..9c6a9fd26812 100644
--- a/drivers/pci/hotplug/cpqphp.h
+++ b/drivers/pci/hotplug/cpqphp.h
@@ -32,6 +32,7 @@
#include <asm/io.h> /* for read? and write? functions */
#include <linux/delay.h> /* for delays */
#include <linux/mutex.h>
+#include <linux/sched.h> /* for signal_pending() */
#define MY_NAME "cpqphp"
diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c
index 855dd7ca47f3..b1e97e682500 100644
--- a/drivers/pci/intel-iommu.c
+++ b/drivers/pci/intel-iommu.c
@@ -48,6 +48,7 @@
#define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
#define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
+#define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
#define IOAPIC_RANGE_START (0xfee00000)
#define IOAPIC_RANGE_END (0xfeefffff)
@@ -94,6 +95,7 @@ static inline unsigned long virt_to_dma_pfn(void *p)
/* global iommu list, set NULL for ignored DMAR units */
static struct intel_iommu **g_iommus;
+static void __init check_tylersburg_isoch(void);
static int rwbf_quirk;
/*
@@ -1934,6 +1936,9 @@ error:
}
static int iommu_identity_mapping;
+#define IDENTMAP_ALL 1
+#define IDENTMAP_GFX 2
+#define IDENTMAP_AZALIA 4
static int iommu_domain_identity_map(struct dmar_domain *domain,
unsigned long long start,
@@ -2151,8 +2156,14 @@ static int domain_add_dev_info(struct dmar_domain *domain,
static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
{
- if (iommu_identity_mapping == 2)
- return IS_GFX_DEVICE(pdev);
+ if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
+ return 1;
+
+ if ((iommu_identity_mapping & IDENTMAP_GFX) && IS_GFX_DEVICE(pdev))
+ return 1;
+
+ if (!(iommu_identity_mapping & IDENTMAP_ALL))
+ return 0;
/*
* We want to start off with all devices in the 1:1 domain, and
@@ -2332,11 +2343,14 @@ int __init init_dmars(void)
}
if (iommu_pass_through)
- iommu_identity_mapping = 1;
+ iommu_identity_mapping |= IDENTMAP_ALL;
+
#ifdef CONFIG_DMAR_BROKEN_GFX_WA
- else
- iommu_identity_mapping = 2;
+ iommu_identity_mapping |= IDENTMAP_GFX;
#endif
+
+ check_tylersburg_isoch();
+
/*
* If pass through is not set or not enabled, setup context entries for
* identity mappings for rmrr, gfx, and isa and may fall back to static
@@ -3670,3 +3684,61 @@ static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
+
+/* On Tylersburg chipsets, some BIOSes have been known to enable the
+ ISOCH DMAR unit for the Azalia sound device, but not give it any
+ TLB entries, which causes it to deadlock. Check for that. We do
+ this in a function called from init_dmars(), instead of in a PCI
+ quirk, because we don't want to print the obnoxious "BIOS broken"
+ message if VT-d is actually disabled.
+*/
+static void __init check_tylersburg_isoch(void)
+{
+ struct pci_dev *pdev;
+ uint32_t vtisochctrl;
+
+ /* If there's no Azalia in the system anyway, forget it. */
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x3a3e, NULL);
+ if (!pdev)
+ return;
+ pci_dev_put(pdev);
+
+ /* System Management Registers. Might be hidden, in which case
+ we can't do the sanity check. But that's OK, because the
+ known-broken BIOSes _don't_ actually hide it, so far. */
+ pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x342e, NULL);
+ if (!pdev)
+ return;
+
+ if (pci_read_config_dword(pdev, 0x188, &vtisochctrl)) {
+ pci_dev_put(pdev);
+ return;
+ }
+
+ pci_dev_put(pdev);
+
+ /* If Azalia DMA is routed to the non-isoch DMAR unit, fine. */
+ if (vtisochctrl & 1)
+ return;
+
+ /* Drop all bits other than the number of TLB entries */
+ vtisochctrl &= 0x1c;
+
+ /* If we have the recommended number of TLB entries (16), fine. */
+ if (vtisochctrl == 0x10)
+ return;
+
+ /* Zero TLB entries? You get to ride the short bus to school. */
+ if (!vtisochctrl) {
+ WARN(1, "Your BIOS is broken; DMA routed to ISOCH DMAR unit but no TLB space.\n"
+ "BIOS vendor: %s; Ver: %s; Product Version: %s\n",
+ dmi_get_system_info(DMI_BIOS_VENDOR),
+ dmi_get_system_info(DMI_BIOS_VERSION),
+ dmi_get_system_info(DMI_PRODUCT_VERSION));
+ iommu_identity_mapping |= IDENTMAP_AZALIA;
+ return;
+ }
+
+ printk(KERN_WARNING "DMAR: Recommended TLB entries for ISOCH unit is 16; your BIOS set %d\n",
+ vtisochctrl);
+}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 6edecff0b419..b36390e02e97 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
@@ -513,7 +522,11 @@ static int pci_raw_set_power_state(struct pci_dev *dev, pci_power_t state)
else if (state == PCI_D2 || dev->current_state == PCI_D2)
udelay(PCI_PM_D2_DELAY);
- dev->current_state = state;
+ pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
+ dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
+ if (dev->current_state != state && printk_ratelimit())
+ dev_info(&dev->dev, "Refused to change power state, "
+ "currently in D%d\n", dev->current_state);
/* According to section 5.4.1 of the "PCI BUS POWER MANAGEMENT
* INTERFACE SPECIFICATION, REV. 1.2", a device transitioning
@@ -1862,31 +1875,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
@@ -1897,13 +1885,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. */
@@ -1924,6 +1911,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
@@ -2542,10 +2547,10 @@ int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
/**
* pci_set_vga_state - set VGA decode state on device and parents if requested
- * @dev the PCI device
- * @decode - true = enable decoding, false = disable decoding
- * @command_bits PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY
- * @change_bridge - traverse ancestors and change bridges
+ * @dev: the PCI device
+ * @decode: true = enable decoding, false = disable decoding
+ * @command_bits: PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY
+ * @change_bridge: traverse ancestors and change bridges
*/
int pci_set_vga_state(struct pci_dev *dev, bool decode,
unsigned int command_bits, bool change_bridge)
@@ -2722,13 +2727,41 @@ int __attribute__ ((weak)) pci_ext_cfg_avail(struct pci_dev *dev)
static int __devinit pci_init(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;
}
+device_initcall(pci_init);
static int __init pci_setup(char *str)
{
@@ -2767,8 +2800,6 @@ static int __init pci_setup(char *str)
}
early_param("pci", pci_setup);
-device_initcall(pci_init);
-
EXPORT_SYMBOL(pci_reenable_device);
EXPORT_SYMBOL(pci_enable_device_io);
EXPORT_SYMBOL(pci_enable_device_mem);
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
index 2ce8f9ccc66e..40c3cc5d1caf 100644
--- a/drivers/pci/pcie/aer/aerdrv.c
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/pm.h>
@@ -52,7 +53,7 @@ static struct pci_error_handlers aer_error_handlers = {
static struct pcie_port_service_driver aerdriver = {
.name = "aer",
- .port_type = PCIE_ANY_PORT,
+ .port_type = PCIE_RC_PORT,
.service = PCIE_PORT_SERVICE_AER,
.probe = aer_probe,
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 6df5c984a791..f635e476d632 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -30,7 +30,6 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
/* global data */
-static const char device_name[] = "pcieport-driver";
static int pcie_portdrv_restore_config(struct pci_dev *dev)
{
@@ -262,7 +261,7 @@ static struct pci_error_handlers pcie_portdrv_err_handler = {
};
static struct pci_driver pcie_portdriver = {
- .name = (char *)device_name,
+ .name = "pcieport",
.id_table = &port_pci_ids[0],
.probe = pcie_portdrv_probe,
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 6099facecd79..a790b1771f9f 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -670,6 +670,25 @@ static void __devinit quirk_vt8235_acpi(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235, quirk_vt8235_acpi);
+/*
+ * TI XIO2000a PCIe-PCI Bridge erroneously reports it supports fast back-to-back:
+ * Disable fast back-to-back on the secondary bus segment
+ */
+static void __devinit quirk_xio2000a(struct pci_dev *dev)
+{
+ struct pci_dev *pdev;
+ u16 command;
+
+ dev_warn(&dev->dev, "TI XIO2000a quirk detected; "
+ "secondary bus fast back-to-back transfers disabled\n");
+ list_for_each_entry(pdev, &dev->subordinate->devices, bus_list) {
+ pci_read_config_word(pdev, PCI_COMMAND, &command);
+ if (command & PCI_COMMAND_FAST_BACK)
+ pci_write_config_word(pdev, PCI_COMMAND, command & ~PCI_COMMAND_FAST_BACK);
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XIO2000A,
+ quirk_xio2000a);
#ifdef CONFIG_X86_IO_APIC
@@ -2572,6 +2591,19 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
}
pci_do_fixups(dev, start, end);
}
+
+static int __init pci_apply_final_quirks(void)
+{
+ struct pci_dev *dev = NULL;
+
+ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ pci_fixup_device(pci_fixup_final, dev);
+ }
+
+ return 0;
+}
+
+fs_initcall_sync(pci_apply_final_quirks);
#else
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev) {}
#endif
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index cb1a027eb552..0959430534b2 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -299,8 +299,17 @@ 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 && !r->parent)
- return r;
+ 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;
+ }
}
return NULL;
}
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 706f82d8111f..c54526b206b5 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -205,43 +205,6 @@ int pci_assign_resource(struct pci_dev *dev, int resno)
return ret;
}
-#if 0
-int pci_assign_resource_fixed(struct pci_dev *dev, int resno)
-{
- struct pci_bus *bus = dev->bus;
- struct resource *res = dev->resource + resno;
- unsigned int type_mask;
- int i, ret = -EBUSY;
-
- type_mask = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH;
-
- for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
- struct resource *r = bus->resource[i];
- if (!r)
- continue;
-
- /* type_mask must match */
- if ((res->flags ^ r->flags) & type_mask)
- continue;
-
- ret = request_resource(r, res);
-
- if (ret == 0)
- break;
- }
-
- if (ret) {
- dev_err(&dev->dev, "BAR %d: can't allocate %s resource %pR\n",
- resno, res->flags & IORESOURCE_IO ? "I/O" : "mem", res);
- } else if (resno < PCI_BRIDGE_RESOURCES) {
- pci_update_resource(dev, resno);
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(pci_assign_resource_fixed);
-#endif
-
/* Sort resources by alignment */
void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
{
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/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/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/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/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 749e2102b2be..d379e74a05d0 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -150,6 +150,8 @@ struct eeepc_hotk {
/* The actual device the driver binds to */
static struct eeepc_hotk *ehotk;
+static void eeepc_rfkill_hotplug(bool real);
+
/* Platform device/driver */
static int eeepc_hotk_thaw(struct device *device);
static int eeepc_hotk_restore(struct device *device);
@@ -343,14 +345,23 @@ static bool eeepc_wlan_rfkill_blocked(void)
static int eeepc_rfkill_set(void *data, bool blocked)
{
unsigned long asl = (unsigned long)data;
- return set_acpi(asl, !blocked);
+ int ret;
+
+ if (asl != CM_ASL_WLAN)
+ return set_acpi(asl, !blocked);
+
+ /* hack to avoid panic with rt2860sta */
+ if (blocked)
+ eeepc_rfkill_hotplug(false);
+ ret = set_acpi(asl, !blocked);
+ return ret;
}
static const struct rfkill_ops eeepc_rfkill_ops = {
.set_block = eeepc_rfkill_set,
};
-static void __init eeepc_enable_camera(void)
+static void __devinit eeepc_enable_camera(void)
{
/*
* If the following call to set_acpi() fails, it's because there's no
@@ -643,13 +654,13 @@ static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
return 0;
}
-static void eeepc_rfkill_hotplug(void)
+static void eeepc_rfkill_hotplug(bool real)
{
struct pci_dev *dev;
struct pci_bus *bus;
- bool blocked = eeepc_wlan_rfkill_blocked();
+ bool blocked = real ? eeepc_wlan_rfkill_blocked() : true;
- if (ehotk->wlan_rfkill)
+ if (real && ehotk->wlan_rfkill)
rfkill_set_sw_state(ehotk->wlan_rfkill, blocked);
mutex_lock(&ehotk->hotplug_lock);
@@ -692,7 +703,7 @@ static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
if (event != ACPI_NOTIFY_BUS_CHECK)
return;
- eeepc_rfkill_hotplug();
+ eeepc_rfkill_hotplug(true);
}
static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
@@ -850,7 +861,7 @@ static int eeepc_hotk_restore(struct device *device)
{
/* Refresh both wlan rfkill state and pci hotplug */
if (ehotk->wlan_rfkill)
- eeepc_rfkill_hotplug();
+ eeepc_rfkill_hotplug(true);
if (ehotk->bluetooth_rfkill)
rfkill_set_sw_state(ehotk->bluetooth_rfkill,
@@ -993,7 +1004,7 @@ static void eeepc_rfkill_exit(void)
* Refresh pci hotplug in case the rfkill state was changed after
* eeepc_unregister_rfkill_notifier()
*/
- eeepc_rfkill_hotplug();
+ eeepc_rfkill_hotplug(true);
if (ehotk->hotplug_slot)
pci_hp_deregister(ehotk->hotplug_slot);
@@ -1109,7 +1120,7 @@ static int eeepc_rfkill_init(struct device *dev)
* Refresh pci hotplug in case the rfkill state was changed during
* setup.
*/
- eeepc_rfkill_hotplug();
+ eeepc_rfkill_hotplug(true);
exit:
if (result && result != -ENODEV)
@@ -1189,7 +1200,7 @@ static int eeepc_input_init(struct device *dev)
return 0;
}
-static int eeepc_hotk_add(struct acpi_device *device)
+static int __devinit eeepc_hotk_add(struct acpi_device *device)
{
struct device *dev;
int result;
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index f35aee5c2149..bcd4ba8be7db 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -944,7 +944,7 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device, int type)
struct fujitsu_hotkey_t *fujitsu_hotkey = acpi_driver_data(device);
struct input_dev *input = fujitsu_hotkey->input;
-#ifdef CONFIG_LEDS_CLASS
+#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
if (fujitsu_hotkey->logolamp_registered)
led_classdev_unregister(&logolamp_led);
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/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/interface.c b/drivers/rtc/interface.c
index 4cdb31a362ca..a0c816238aa9 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -12,6 +12,7 @@
*/
#include <linux/rtc.h>
+#include <linux/sched.h>
#include <linux/log2.h>
int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 8a11de9552cd..62227cd52410 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/rtc.h>
+#include <linux/sched.h>
#include "rtc-core.h"
static dev_t rtc_devt;
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-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/s390/block/dasd.c b/drivers/s390/block/dasd.c
index dad0449475b6..aaccc8ecfa8f 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2508,8 +2508,6 @@ int dasd_generic_restore_device(struct ccw_device *cdev)
device->stopped &= ~DASD_UNRESUMED_PM;
dasd_schedule_device_bh(device);
- if (device->block)
- dasd_schedule_block_bh(device->block);
if (device->discipline->restore)
rc = device->discipline->restore(device);
@@ -2520,6 +2518,9 @@ int dasd_generic_restore_device(struct ccw_device *cdev)
*/
device->stopped |= DASD_UNRESUMED_PM;
+ if (device->block)
+ dasd_schedule_block_bh(device->block);
+
dasd_put_device(device);
return 0;
}
@@ -2532,6 +2533,7 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
{
struct dasd_ccw_req *cqr;
struct ccw1 *ccw;
+ unsigned long *idaw;
cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device);
@@ -2545,9 +2547,17 @@ static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device,
ccw = cqr->cpaddr;
ccw->cmd_code = CCW_CMD_RDC;
- ccw->cda = (__u32)(addr_t)rdc_buffer;
- ccw->count = rdc_buffer_size;
+ if (idal_is_needed(rdc_buffer, rdc_buffer_size)) {
+ idaw = (unsigned long *) (cqr->data);
+ ccw->cda = (__u32)(addr_t) idaw;
+ ccw->flags = CCW_FLAG_IDA;
+ idaw = idal_create_words(idaw, rdc_buffer, rdc_buffer_size);
+ } else {
+ ccw->cda = (__u32)(addr_t) rdc_buffer;
+ ccw->flags = 0;
+ }
+ ccw->count = rdc_buffer_size;
cqr->startdev = device;
cqr->memdev = device;
cqr->expires = 10*HZ;
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 4e49b4a6c880..8174ec921769 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -145,6 +145,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 +442,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 ab3521755588..417b97cd3f94 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -2338,6 +2338,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev,
/* Calculate number of blocks/records per track. */
blksize = block->bp_block;
blk_per_trk = recs_per_track(&private->rdc_data, 0, blksize);
+ if (blk_per_trk == 0)
+ return ERR_PTR(-EINVAL);
/* Calculate record id of first and last block. */
first_rec = first_trk = blk_rq_pos(req) >> block->s2b_shift;
first_offs = sector_div(first_trk, blk_per_trk);
@@ -3211,8 +3213,10 @@ int dasd_eckd_pm_freeze(struct dasd_device *device)
int dasd_eckd_restore_device(struct dasd_device *device)
{
struct dasd_eckd_private *private;
+ struct dasd_eckd_characteristics temp_rdc_data;
int is_known, rc;
struct dasd_uid temp_uid;
+ unsigned long flags;
private = (struct dasd_eckd_private *) device->private;
@@ -3225,7 +3229,8 @@ int dasd_eckd_restore_device(struct dasd_device *device)
rc = dasd_eckd_generate_uid(device, &private->uid);
dasd_get_uid(device->cdev, &temp_uid);
if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0)
- dev_err(&device->cdev->dev, "The UID of the DASD has changed\n");
+ dev_err(&device->cdev->dev, "The UID of the DASD has "
+ "changed\n");
if (rc)
goto out_err;
dasd_set_uid(device->cdev, &private->uid);
@@ -3245,15 +3250,17 @@ int dasd_eckd_restore_device(struct dasd_device *device)
dasd_eckd_read_features(device);
/* Read Device Characteristics */
- memset(&private->rdc_data, 0, sizeof(private->rdc_data));
rc = dasd_generic_read_dev_chars(device, DASD_ECKD_MAGIC,
- &private->rdc_data, 64);
+ &temp_rdc_data, 64);
if (rc) {
DBF_EVENT(DBF_WARNING,
"Read device characteristics failed, rc=%d for "
"device: %s", rc, dev_name(&device->cdev->dev));
goto out_err;
}
+ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
+ memcpy(&private->rdc_data, &temp_rdc_data, sizeof(temp_rdc_data));
+ spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
/* add device to alias management */
dasd_alias_add_device(device);
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index d6a022f55e92..62ddf5202b79 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -1361,11 +1361,13 @@ static int raw3270_pm_start(struct ccw_device *cdev)
void raw3270_pm_unfreeze(struct raw3270_view *view)
{
+#ifdef CONFIG_TN3270_CONSOLE
struct raw3270 *rp;
rp = view->dev;
if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags))
ccw_device_force_console();
+#endif
}
static struct ccw_device_id raw3270_id[] = {
diff --git a/drivers/s390/char/sclp_async.c b/drivers/s390/char/sclp_async.c
index daaec185ed36..a4f68e5b9c96 100644
--- a/drivers/s390/char/sclp_async.c
+++ b/drivers/s390/char/sclp_async.c
@@ -62,7 +62,7 @@ static struct notifier_block call_home_panic_nb = {
.priority = INT_MAX,
};
-static int proc_handler_callhome(ctl_table *ctl, int write, struct file *filp,
+static int proc_handler_callhome(struct ctl_table *ctl, int write,
void __user *buffer, size_t *count,
loff_t *ppos)
{
@@ -100,7 +100,7 @@ static struct ctl_table callhome_table[] = {
{
.procname = "callhome",
.mode = 0644,
- .proc_handler = &proc_handler_callhome,
+ .proc_handler = proc_handler_callhome,
},
{ .ctl_name = 0 }
};
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 178724f2a4c3..b9d2a007e93b 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -705,21 +705,6 @@ out_driver:
}
__initcall(sclp_vt220_tty_init);
-#ifdef CONFIG_SCLP_VT220_CONSOLE
-
-static void
-sclp_vt220_con_write(struct console *con, const char *buf, unsigned int count)
-{
- __sclp_vt220_write((const unsigned char *) buf, count, 1, 1, 0);
-}
-
-static struct tty_driver *
-sclp_vt220_con_device(struct console *c, int *index)
-{
- *index = 0;
- return sclp_vt220_driver;
-}
-
static void __sclp_vt220_flush_buffer(void)
{
unsigned long flags;
@@ -776,6 +761,21 @@ static void sclp_vt220_pm_event_fn(struct sclp_register *reg,
}
}
+#ifdef CONFIG_SCLP_VT220_CONSOLE
+
+static void
+sclp_vt220_con_write(struct console *con, const char *buf, unsigned int count)
+{
+ __sclp_vt220_write((const unsigned char *) buf, count, 1, 1, 0);
+}
+
+static struct tty_driver *
+sclp_vt220_con_device(struct console *c, int *index)
+{
+ *index = 0;
+ return sclp_vt220_driver;
+}
+
static int
sclp_vt220_notify(struct notifier_block *self,
unsigned long event, void *data)
diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c
index 64f57ef2763c..0c0705b91c28 100644
--- a/drivers/s390/char/tape_block.c
+++ b/drivers/s390/char/tape_block.c
@@ -162,9 +162,10 @@ tapeblock_requeue(struct work_struct *work) {
spin_lock_irq(&device->blk_data.request_queue_lock);
while (
!blk_queue_plugged(queue) &&
- (req = blk_fetch_request(queue)) &&
+ blk_peek_request(queue) &&
nr_queued < TAPEBLOCK_MIN_REQUEUE
) {
+ req = blk_fetch_request(queue);
if (rq_data_dir(req) == WRITE) {
DBF_EVENT(1, "TBLOCK: Rejecting write request\n");
spin_unlock_irq(&device->blk_data.request_queue_lock);
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 6565f027791e..7eab9ab9f406 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -265,13 +265,11 @@ struct ccwdev_iter {
static void *
cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
{
- struct ccwdev_iter *iter;
+ struct ccwdev_iter *iter = s->private;
if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
return NULL;
- iter = kzalloc(sizeof(struct ccwdev_iter), GFP_KERNEL);
- if (!iter)
- return ERR_PTR(-ENOMEM);
+ memset(iter, 0, sizeof(*iter));
iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
return iter;
@@ -280,8 +278,6 @@ cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
static void
cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
{
- if (!IS_ERR(it))
- kfree(it);
}
static void *
@@ -378,14 +374,15 @@ static const struct seq_operations cio_ignore_proc_seq_ops = {
static int
cio_ignore_proc_open(struct inode *inode, struct file *file)
{
- return seq_open(file, &cio_ignore_proc_seq_ops);
+ return seq_open_private(file, &cio_ignore_proc_seq_ops,
+ sizeof(struct ccwdev_iter));
}
static const struct file_operations cio_ignore_proc_fops = {
.open = cio_ignore_proc_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = seq_release_private,
.write = cio_ignore_write,
};
diff --git a/drivers/s390/cio/chp.c b/drivers/s390/cio/chp.c
index 40002830d48a..8ab51608da55 100644
--- a/drivers/s390/cio/chp.c
+++ b/drivers/s390/cio/chp.c
@@ -393,7 +393,6 @@ int chp_new(struct chp_id chpid)
chp->state = 1;
chp->dev.parent = &channel_subsystems[chpid.cssid]->device;
chp->dev.release = chp_release;
- dev_set_name(&chp->dev, "chp%x.%02x", chpid.cssid, chpid.id);
/* Obtain channel path description and fill it in. */
ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc);
@@ -411,6 +410,7 @@ int chp_new(struct chp_id chpid)
} else {
chp->cmg = -1;
}
+ dev_set_name(&chp->dev, "chp%x.%02x", chpid.cssid, chpid.id);
/* make it known to the system */
ret = device_register(&chp->dev);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index f780bdd3a04e..2490b741e16a 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -1250,8 +1250,7 @@ static int io_subchannel_probe(struct subchannel *sch)
unsigned long flags;
struct ccw_dev_id dev_id;
- cdev = sch_get_cdev(sch);
- if (cdev) {
+ if (cio_is_console(sch->schid)) {
rc = sysfs_create_group(&sch->dev.kobj,
&io_subchannel_attr_group);
if (rc)
@@ -1260,13 +1259,13 @@ static int io_subchannel_probe(struct subchannel *sch)
"0.%x.%04x (rc=%d)\n",
sch->schid.ssid, sch->schid.sch_no, rc);
/*
- * This subchannel already has an associated ccw_device.
+ * The console subchannel already has an associated ccw_device.
* Throw the delayed uevent for the subchannel, register
- * the ccw_device and exit. This happens for all early
- * devices, e.g. the console.
+ * the ccw_device and exit.
*/
dev_set_uevent_suppress(&sch->dev, 0);
kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
+ cdev = sch_get_cdev(sch);
cdev->dev.groups = ccwdev_attr_groups;
device_initialize(&cdev->dev);
ccw_device_register(cdev);
@@ -1609,7 +1608,7 @@ int ccw_purge_blacklisted(void)
return 0;
}
-static void device_set_disconnected(struct ccw_device *cdev)
+void ccw_device_set_disconnected(struct ccw_device *cdev)
{
if (!cdev)
return;
@@ -1705,7 +1704,7 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow)
ccw_device_trigger_reprobe(cdev);
break;
case DISC:
- device_set_disconnected(cdev);
+ ccw_device_set_disconnected(cdev);
break;
default:
break;
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index ed39a2caaf47..246c6482842c 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -125,6 +125,7 @@ int ccw_device_stlck(struct ccw_device *);
void ccw_device_trigger_reprobe(struct ccw_device *);
void ccw_device_kill_io(struct ccw_device *);
int ccw_device_notify(struct ccw_device *, int);
+void ccw_device_set_disconnected(struct ccw_device *cdev);
void ccw_device_set_notoper(struct ccw_device *cdev);
/* qdio needs this. */
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index e728ce447f6e..b9613d7df9ef 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -387,19 +387,35 @@ ccw_device_done(struct ccw_device *cdev, int state)
cdev->private->state = state;
- if (state == DEV_STATE_BOXED) {
+ switch (state) {
+ case DEV_STATE_BOXED:
CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
cdev->private->dev_id.devno, sch->schid.sch_no);
if (cdev->online && !ccw_device_notify(cdev, CIO_BOXED))
ccw_device_schedule_sch_unregister(cdev);
cdev->private->flags.donotify = 0;
- }
- if (state == DEV_STATE_NOT_OPER) {
+ break;
+ case DEV_STATE_NOT_OPER:
CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n",
cdev->private->dev_id.devno, sch->schid.sch_no);
if (!ccw_device_notify(cdev, CIO_GONE))
ccw_device_schedule_sch_unregister(cdev);
+ else
+ ccw_device_set_disconnected(cdev);
cdev->private->flags.donotify = 0;
+ break;
+ case DEV_STATE_DISCONNECTED:
+ CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel "
+ "%04x\n", cdev->private->dev_id.devno,
+ sch->schid.sch_no);
+ if (!ccw_device_notify(cdev, CIO_NO_PATH))
+ ccw_device_schedule_sch_unregister(cdev);
+ else
+ ccw_device_set_disconnected(cdev);
+ cdev->private->flags.donotify = 0;
+ break;
+ default:
+ break;
}
if (cdev->private->flags.donotify) {
@@ -671,6 +687,10 @@ ccw_device_offline(struct ccw_device *cdev)
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
return 0;
}
+ if (cdev->private->state == DEV_STATE_BOXED) {
+ ccw_device_done(cdev, DEV_STATE_BOXED);
+ return 0;
+ }
if (ccw_device_is_orphan(cdev)) {
ccw_device_done(cdev, DEV_STATE_OFFLINE);
return 0;
@@ -730,11 +750,10 @@ ccw_device_recog_notoper(struct ccw_device *cdev, enum dev_event dev_event)
static void ccw_device_generic_notoper(struct ccw_device *cdev,
enum dev_event dev_event)
{
- struct subchannel *sch;
-
- ccw_device_set_notoper(cdev);
- sch = to_subchannel(cdev->dev.parent);
- css_schedule_eval(sch->schid);
+ if (!ccw_device_notify(cdev, CIO_GONE))
+ ccw_device_schedule_sch_unregister(cdev);
+ else
+ ccw_device_set_disconnected(cdev);
}
/*
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index c20d4790258e..5677b40e4ac0 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -361,7 +361,7 @@ static void rng_type6CPRB_msgX(struct ap_device *ap_dev,
.ToCardLen1 = sizeof *msg - sizeof(msg->hdr),
.FromCardLen1 = sizeof *msg - sizeof(msg->hdr),
};
- static struct CPRBX static_cprbx = {
+ static struct CPRBX local_cprbx = {
.cprb_len = 0x00dc,
.cprb_ver_id = 0x02,
.func_id = {0x54, 0x32},
@@ -372,7 +372,7 @@ static void rng_type6CPRB_msgX(struct ap_device *ap_dev,
msg->hdr = static_type6_hdrX;
msg->hdr.FromCardLen2 = random_number_length,
- msg->cprbx = static_cprbx;
+ msg->cprbx = local_cprbx;
msg->cprbx.rpl_datal = random_number_length,
msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid);
memcpy(msg->function_code, msg->hdr.function_code, 0x02);
@@ -561,7 +561,8 @@ static int convert_response_ica(struct zcrypt_device *zdev,
if (msg->cprbx.cprb_ver_id == 0x02)
return convert_type86_ica(zdev, reply,
outputdata, outputdatalength);
- /* no break, incorrect cprb version is an unknown response */
+ /* Fall through, no break, incorrect cprb version is an unknown
+ * response */
default: /* Unknown response type, this should NEVER EVER happen */
zdev->online = 0;
return -EAGAIN; /* repeat the request on a different device. */
@@ -587,7 +588,8 @@ static int convert_response_xcrb(struct zcrypt_device *zdev,
}
if (msg->cprbx.cprb_ver_id == 0x02)
return convert_type86_xcrb(zdev, reply, xcRB);
- /* no break, incorrect cprb version is an unknown response */
+ /* Fall through, no break, incorrect cprb version is an unknown
+ * response */
default: /* Unknown response type, this should NEVER EVER happen */
xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
zdev->online = 0;
@@ -610,7 +612,8 @@ static int convert_response_rng(struct zcrypt_device *zdev,
return -EINVAL;
if (msg->cprbx.cprb_ver_id == 0x02)
return convert_type86_rng(zdev, reply, data);
- /* no break, incorrect cprb version is an unknown response */
+ /* Fall through, no break, incorrect cprb version is an unknown
+ * response */
default: /* Unknown response type, this should NEVER EVER happen */
zdev->online = 0;
return -EAGAIN; /* repeat the request on a different device. */
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/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 1be6bf7e8ce6..0f79f3af4f54 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -80,28 +80,35 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun)
{
+ struct ccw_device *ccwdev;
struct zfcp_adapter *adapter;
struct zfcp_port *port;
struct zfcp_unit *unit;
- mutex_lock(&zfcp_data.config_mutex);
- read_lock_irq(&zfcp_data.config_lock);
- adapter = zfcp_get_adapter_by_busid(busid);
- if (adapter)
- zfcp_adapter_get(adapter);
- read_unlock_irq(&zfcp_data.config_lock);
+ ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
+ if (!ccwdev)
+ return;
+
+ if (ccw_device_set_online(ccwdev))
+ goto out_ccwdev;
+ mutex_lock(&zfcp_data.config_mutex);
+ adapter = dev_get_drvdata(&ccwdev->dev);
if (!adapter)
- goto out_adapter;
- port = zfcp_port_enqueue(adapter, wwpn, 0, 0);
- if (IS_ERR(port))
+ goto out_unlock;
+ zfcp_adapter_get(adapter);
+
+ port = zfcp_get_port_by_wwpn(adapter, wwpn);
+ if (!port)
goto out_port;
+
+ zfcp_port_get(port);
unit = zfcp_unit_enqueue(port, lun);
if (IS_ERR(unit))
goto out_unit;
mutex_unlock(&zfcp_data.config_mutex);
- ccw_device_set_online(adapter->ccw_device);
+ zfcp_erp_unit_reopen(unit, 0, "auidc_1", NULL);
zfcp_erp_wait(adapter);
flush_work(&unit->scsi_work);
@@ -111,8 +118,10 @@ out_unit:
zfcp_port_put(port);
out_port:
zfcp_adapter_put(adapter);
-out_adapter:
+out_unlock:
mutex_unlock(&zfcp_data.config_mutex);
+out_ccwdev:
+ put_device(&ccwdev->dev);
return;
}
@@ -593,10 +602,8 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
int retval = 0;
unsigned long flags;
- cancel_work_sync(&adapter->scan_work);
cancel_work_sync(&adapter->stat_work);
zfcp_fc_wka_ports_force_offline(adapter->gs);
- zfcp_adapter_scsi_unregister(adapter);
sysfs_remove_group(&adapter->ccw_device->dev.kobj,
&zfcp_sysfs_adapter_attrs);
dev_set_drvdata(&adapter->ccw_device->dev, NULL);
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index 0c90f8e71605..e08339428ecf 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -102,6 +102,14 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
adapter = dev_get_drvdata(&ccw_device->dev);
if (!adapter)
goto out;
+ mutex_unlock(&zfcp_data.config_mutex);
+
+ cancel_work_sync(&adapter->scan_work);
+
+ mutex_lock(&zfcp_data.config_mutex);
+
+ /* this also removes the scsi devices, so call it first */
+ zfcp_adapter_scsi_unregister(adapter);
write_lock_irq(&zfcp_data.config_lock);
list_for_each_entry_safe(port, p, &adapter->port_list_head, list) {
@@ -117,11 +125,8 @@ static void zfcp_ccw_remove(struct ccw_device *ccw_device)
write_unlock_irq(&zfcp_data.config_lock);
list_for_each_entry_safe(port, p, &port_remove_lh, list) {
- list_for_each_entry_safe(unit, u, &unit_remove_lh, list) {
- if (unit->device)
- scsi_remove_device(unit->device);
+ list_for_each_entry_safe(unit, u, &unit_remove_lh, list)
zfcp_unit_dequeue(unit);
- }
zfcp_port_dequeue(port);
}
wait_event(adapter->remove_wq, atomic_read(&adapter->refcount) == 0);
@@ -192,13 +197,9 @@ static int zfcp_ccw_set_offline(struct ccw_device *ccw_device)
mutex_lock(&zfcp_data.config_mutex);
adapter = dev_get_drvdata(&ccw_device->dev);
- if (!adapter)
- goto out;
-
zfcp_erp_adapter_shutdown(adapter, 0, "ccsoff1", NULL);
zfcp_erp_wait(adapter);
mutex_unlock(&zfcp_data.config_mutex);
-out:
return 0;
}
@@ -253,13 +254,17 @@ static void zfcp_ccw_shutdown(struct ccw_device *cdev)
mutex_lock(&zfcp_data.config_mutex);
adapter = dev_get_drvdata(&cdev->dev);
+ if (!adapter)
+ goto out;
+
zfcp_erp_adapter_shutdown(adapter, 0, "ccshut1", NULL);
zfcp_erp_wait(adapter);
zfcp_erp_thread_kill(adapter);
+out:
mutex_unlock(&zfcp_data.config_mutex);
}
-static struct ccw_driver zfcp_ccw_driver = {
+struct ccw_driver zfcp_ccw_driver = {
.owner = THIS_MODULE,
.name = "zfcp",
.ids = zfcp_ccw_device_id,
@@ -284,20 +289,3 @@ int __init zfcp_ccw_register(void)
{
return ccw_driver_register(&zfcp_ccw_driver);
}
-
-/**
- * zfcp_get_adapter_by_busid - find zfcp_adapter struct
- * @busid: bus id string of zfcp adapter to find
- */
-struct zfcp_adapter *zfcp_get_adapter_by_busid(char *busid)
-{
- struct ccw_device *ccw_device;
- struct zfcp_adapter *adapter = NULL;
-
- ccw_device = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
- if (ccw_device) {
- adapter = dev_get_drvdata(&ccw_device->dev);
- put_device(&ccw_device->dev);
- }
- return adapter;
-}
diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c
index 8305c874e86f..ef681dfed0cc 100644
--- a/drivers/s390/scsi/zfcp_cfdc.c
+++ b/drivers/s390/scsi/zfcp_cfdc.c
@@ -86,8 +86,23 @@ static int zfcp_cfdc_copy_to_user(void __user *user_buffer,
static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno)
{
char busid[9];
+ struct ccw_device *ccwdev;
+ struct zfcp_adapter *adapter = NULL;
+
snprintf(busid, sizeof(busid), "0.0.%04x", devno);
- return zfcp_get_adapter_by_busid(busid);
+ ccwdev = get_ccwdev_by_busid(&zfcp_ccw_driver, busid);
+ if (!ccwdev)
+ goto out;
+
+ adapter = dev_get_drvdata(&ccwdev->dev);
+ if (!adapter)
+ goto out_put;
+
+ zfcp_adapter_get(adapter);
+out_put:
+ put_device(&ccwdev->dev);
+out:
+ return adapter;
}
static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc *fsf_cfdc, int command)
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index 36935bc0818f..629edec70405 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -28,7 +28,7 @@ extern int zfcp_sg_setup_table(struct scatterlist *, int);
/* zfcp_ccw.c */
extern int zfcp_ccw_register(void);
extern int zfcp_ccw_priv_sch(struct zfcp_adapter *);
-extern struct zfcp_adapter *zfcp_get_adapter_by_busid(char *);
+extern struct ccw_driver zfcp_ccw_driver;
/* zfcp_cfdc.c */
extern struct miscdevice zfcp_cfdc_misc;
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index f09c863dc6bd..38a7e4a6b639 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -1058,11 +1058,25 @@ static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req,
bytes = zfcp_qdio_sbals_from_sg(adapter->qdio, &req->queue_req,
SBAL_FLAGS0_TYPE_WRITE_READ,
sg_resp, max_sbals);
+ req->qtcb->bottom.support.resp_buf_length = bytes;
if (bytes <= 0)
return -EIO;
+ return 0;
+}
+
+static int zfcp_fsf_setup_ct_els(struct zfcp_fsf_req *req,
+ struct scatterlist *sg_req,
+ struct scatterlist *sg_resp,
+ int max_sbals)
+{
+ int ret;
+
+ ret = zfcp_fsf_setup_ct_els_sbals(req, sg_req, sg_resp, max_sbals);
+ if (ret)
+ return ret;
+
/* common settings for ct/gs and els requests */
- req->qtcb->bottom.support.resp_buf_length = bytes;
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);
@@ -1094,8 +1108,8 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool)
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp,
- FSF_MAX_SBALS_PER_REQ);
+ ret = zfcp_fsf_setup_ct_els(req, ct->req, ct->resp,
+ FSF_MAX_SBALS_PER_REQ);
if (ret)
goto failed_send;
@@ -1192,7 +1206,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els)
}
req->status |= ZFCP_STATUS_FSFREQ_CLEANUP;
- ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2);
+ ret = zfcp_fsf_setup_ct_els(req, els->req, els->resp, 2);
if (ret)
goto failed_send;
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index faa0fcfed71e..4e916502a7eb 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -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/Kconfig b/drivers/scsi/Kconfig
index 82bb3b2d207a..e11cca4c784c 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -366,6 +366,7 @@ config ISCSI_TCP
source "drivers/scsi/cxgb3i/Kconfig"
source "drivers/scsi/bnx2i/Kconfig"
+source "drivers/scsi/be2iscsi/Kconfig"
config SGIWD93_SCSI
tristate "SGI WD93C93 SCSI Driver"
@@ -1827,6 +1828,16 @@ config SCSI_SRP
To compile this driver as a module, choose M here: the
module will be called libsrp.
+config SCSI_BFA_FC
+ tristate "Brocade BFA Fibre Channel Support"
+ depends on PCI && SCSI
+ select SCSI_FC_ATTRS
+ help
+ This bfa driver supports all Brocade PCIe FC/FCOE host adapters.
+
+ To compile this driver as a module, choose M here. The module will
+ be called bfa.
+
endif # SCSI_LOWLEVEL
source "drivers/scsi/pcmcia/Kconfig"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 61a94af3cee7..3ad61db5e3fa 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -86,6 +86,7 @@ obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/
obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/
+obj-$(CONFIG_SCSI_BFA_FC) += bfa/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
obj-$(CONFIG_SCSI_T128) += t128.o
obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o
@@ -130,6 +131,7 @@ obj-$(CONFIG_SCSI_MVSAS) += mvsas/
obj-$(CONFIG_PS3_ROM) += ps3rom.o
obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgb3i/
obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
+obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/
obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
obj-$(CONFIG_ARM) += arm/
diff --git a/drivers/scsi/be2iscsi/Kconfig b/drivers/scsi/be2iscsi/Kconfig
new file mode 100644
index 000000000000..2952fcd008ea
--- /dev/null
+++ b/drivers/scsi/be2iscsi/Kconfig
@@ -0,0 +1,8 @@
+config BE2ISCSI
+ tristate "ServerEngines' 10Gbps iSCSI - BladeEngine 2"
+ depends on PCI && SCSI
+ select SCSI_ISCSI_ATTRS
+
+ help
+ This driver implements the iSCSI functionality for ServerEngines'
+ 10Gbps Storage adapter - BladeEngine 2.
diff --git a/drivers/scsi/be2iscsi/Makefile b/drivers/scsi/be2iscsi/Makefile
new file mode 100644
index 000000000000..c11f443e3f83
--- /dev/null
+++ b/drivers/scsi/be2iscsi/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile to build the iSCSI driver for ServerEngine's BladeEngine.
+#
+#
+
+obj-$(CONFIG_BE2ISCSI) += be2iscsi.o
+
+be2iscsi-y := be_iscsi.o be_main.o be_mgmt.o be_cmds.o
diff --git a/drivers/scsi/be2iscsi/be.h b/drivers/scsi/be2iscsi/be.h
new file mode 100644
index 000000000000..b36020dcf012
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be.h
@@ -0,0 +1,183 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * 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. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+#ifndef BEISCSI_H
+#define BEISCSI_H
+
+#include <linux/pci.h>
+#include <linux/if_vlan.h>
+
+#define FW_VER_LEN 32
+
+struct be_dma_mem {
+ void *va;
+ dma_addr_t dma;
+ u32 size;
+};
+
+struct be_queue_info {
+ struct be_dma_mem dma_mem;
+ u16 len;
+ u16 entry_size; /* Size of an element in the queue */
+ u16 id;
+ u16 tail, head;
+ bool created;
+ atomic_t used; /* Number of valid elements in the queue */
+};
+
+static inline u32 MODULO(u16 val, u16 limit)
+{
+ WARN_ON(limit & (limit - 1));
+ return val & (limit - 1);
+}
+
+static inline void index_inc(u16 *index, u16 limit)
+{
+ *index = MODULO((*index + 1), limit);
+}
+
+static inline void *queue_head_node(struct be_queue_info *q)
+{
+ return q->dma_mem.va + q->head * q->entry_size;
+}
+
+static inline void *queue_tail_node(struct be_queue_info *q)
+{
+ return q->dma_mem.va + q->tail * q->entry_size;
+}
+
+static inline void queue_head_inc(struct be_queue_info *q)
+{
+ index_inc(&q->head, q->len);
+}
+
+static inline void queue_tail_inc(struct be_queue_info *q)
+{
+ index_inc(&q->tail, q->len);
+}
+
+/*ISCSI */
+
+struct be_eq_obj {
+ struct be_queue_info q;
+ char desc[32];
+
+ /* Adaptive interrupt coalescing (AIC) info */
+ bool enable_aic;
+ u16 min_eqd; /* in usecs */
+ u16 max_eqd; /* in usecs */
+ u16 cur_eqd; /* in usecs */
+};
+
+struct be_mcc_obj {
+ struct be_queue_info *q;
+ struct be_queue_info *cq;
+};
+
+struct be_ctrl_info {
+ u8 __iomem *csr;
+ u8 __iomem *db; /* Door Bell */
+ u8 __iomem *pcicfg; /* PCI config space */
+ struct pci_dev *pdev;
+
+ /* Mbox used for cmd request/response */
+ spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */
+ struct be_dma_mem mbox_mem;
+ /* Mbox mem is adjusted to align to 16 bytes. The allocated addr
+ * is stored for freeing purpose */
+ struct be_dma_mem mbox_mem_alloced;
+
+ /* MCC Rings */
+ struct be_mcc_obj mcc_obj;
+ spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */
+ spinlock_t mcc_cq_lock;
+
+ /* MCC Async callback */
+ void (*async_cb) (void *adapter, bool link_up);
+ void *adapter_ctxt;
+};
+
+#include "be_cmds.h"
+
+#define PAGE_SHIFT_4K 12
+#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K)
+
+/* Returns number of pages spanned by the data starting at the given addr */
+#define PAGES_4K_SPANNED(_address, size) \
+ ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \
+ (size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K))
+
+/* Byte offset into the page corresponding to given address */
+#define OFFSET_IN_PAGE(addr) \
+ ((size_t)(addr) & (PAGE_SIZE_4K-1))
+
+/* Returns bit offset within a DWORD of a bitfield */
+#define AMAP_BIT_OFFSET(_struct, field) \
+ (((size_t)&(((_struct *)0)->field))%32)
+
+/* Returns the bit mask of the field that is NOT shifted into location. */
+static inline u32 amap_mask(u32 bitsize)
+{
+ return (bitsize == 32 ? 0xFFFFFFFF : (1 << bitsize) - 1);
+}
+
+static inline void amap_set(void *ptr, u32 dw_offset, u32 mask,
+ u32 offset, u32 value)
+{
+ u32 *dw = (u32 *) ptr + dw_offset;
+ *dw &= ~(mask << offset);
+ *dw |= (mask & value) << offset;
+}
+
+#define AMAP_SET_BITS(_struct, field, ptr, val) \
+ amap_set(ptr, \
+ offsetof(_struct, field)/32, \
+ amap_mask(sizeof(((_struct *)0)->field)), \
+ AMAP_BIT_OFFSET(_struct, field), \
+ val)
+
+static inline u32 amap_get(void *ptr, u32 dw_offset, u32 mask, u32 offset)
+{
+ u32 *dw = ptr;
+ return mask & (*(dw + dw_offset) >> offset);
+}
+
+#define AMAP_GET_BITS(_struct, field, ptr) \
+ amap_get(ptr, \
+ offsetof(_struct, field)/32, \
+ amap_mask(sizeof(((_struct *)0)->field)), \
+ AMAP_BIT_OFFSET(_struct, field))
+
+#define be_dws_cpu_to_le(wrb, len) swap_dws(wrb, len)
+#define be_dws_le_to_cpu(wrb, len) swap_dws(wrb, len)
+static inline void swap_dws(void *wrb, int len)
+{
+#ifdef __BIG_ENDIAN
+ u32 *dw = wrb;
+ WARN_ON(len % 4);
+ do {
+ *dw = cpu_to_le32(*dw);
+ dw++;
+ len -= 4;
+ } while (len);
+#endif /* __BIG_ENDIAN */
+}
+
+extern void beiscsi_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm,
+ u16 num_popped);
+
+#endif /* BEISCSI_H */
diff --git a/drivers/scsi/be2iscsi/be_cmds.c b/drivers/scsi/be2iscsi/be_cmds.c
new file mode 100644
index 000000000000..08007b6e42df
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_cmds.c
@@ -0,0 +1,523 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * 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. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+#include "be.h"
+#include "be_mgmt.h"
+#include "be_main.h"
+
+static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl)
+{
+ if (compl->flags != 0) {
+ compl->flags = le32_to_cpu(compl->flags);
+ WARN_ON((compl->flags & CQE_FLAGS_VALID_MASK) == 0);
+ return true;
+ } else
+ return false;
+}
+
+static inline void be_mcc_compl_use(struct be_mcc_compl *compl)
+{
+ compl->flags = 0;
+}
+
+static int be_mcc_compl_process(struct be_ctrl_info *ctrl,
+ struct be_mcc_compl *compl)
+{
+ u16 compl_status, extd_status;
+
+ be_dws_le_to_cpu(compl, 4);
+
+ compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) &
+ CQE_STATUS_COMPL_MASK;
+ if (compl_status != MCC_STATUS_SUCCESS) {
+ extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) &
+ CQE_STATUS_EXTD_MASK;
+ dev_err(&ctrl->pdev->dev,
+ "error in cmd completion: status(compl/extd)=%d/%d\n",
+ compl_status, extd_status);
+ return -1;
+ }
+ return 0;
+}
+
+static inline bool is_link_state_evt(u32 trailer)
+{
+ return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) &
+ ASYNC_TRAILER_EVENT_CODE_MASK) == ASYNC_EVENT_CODE_LINK_STATE);
+}
+
+void beiscsi_cq_notify(struct be_ctrl_info *ctrl, u16 qid, bool arm,
+ u16 num_popped)
+{
+ u32 val = 0;
+ val |= qid & DB_CQ_RING_ID_MASK;
+ if (arm)
+ val |= 1 << DB_CQ_REARM_SHIFT;
+ val |= num_popped << DB_CQ_NUM_POPPED_SHIFT;
+ iowrite32(val, ctrl->db + DB_CQ_OFFSET);
+}
+
+static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl)
+{
+#define long_delay 2000
+ void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
+ int cnt = 0, wait = 5; /* in usecs */
+ u32 ready;
+
+ do {
+ ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
+ if (ready)
+ break;
+
+ if (cnt > 6000000) {
+ dev_err(&ctrl->pdev->dev, "mbox_db poll timed out\n");
+ return -1;
+ }
+
+ if (cnt > 50) {
+ wait = long_delay;
+ mdelay(long_delay / 1000);
+ } else
+ udelay(wait);
+ cnt += wait;
+ } while (true);
+ return 0;
+}
+
+int be_mbox_notify(struct be_ctrl_info *ctrl)
+{
+ int status;
+ u32 val = 0;
+ void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
+ struct be_dma_mem *mbox_mem = &ctrl->mbox_mem;
+ struct be_mcc_mailbox *mbox = mbox_mem->va;
+ struct be_mcc_compl *compl = &mbox->compl;
+
+ val &= ~MPU_MAILBOX_DB_RDY_MASK;
+ val |= MPU_MAILBOX_DB_HI_MASK;
+ val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
+ iowrite32(val, db);
+
+ status = be_mbox_db_ready_wait(ctrl);
+ if (status != 0) {
+ SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 1\n");
+ return status;
+ }
+ val = 0;
+ val &= ~MPU_MAILBOX_DB_RDY_MASK;
+ val &= ~MPU_MAILBOX_DB_HI_MASK;
+ val |= (u32) (mbox_mem->dma >> 4) << 2;
+ iowrite32(val, db);
+
+ status = be_mbox_db_ready_wait(ctrl);
+ if (status != 0) {
+ SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed 2\n");
+ return status;
+ }
+ if (be_mcc_compl_is_new(compl)) {
+ status = be_mcc_compl_process(ctrl, &mbox->compl);
+ be_mcc_compl_use(compl);
+ if (status) {
+ SE_DEBUG(DBG_LVL_1, "After be_mcc_compl_process \n");
+ return status;
+ }
+ } else {
+ dev_err(&ctrl->pdev->dev, "invalid mailbox completion\n");
+ return -1;
+ }
+ return 0;
+}
+
+void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
+ bool embedded, u8 sge_cnt)
+{
+ if (embedded)
+ wrb->embedded |= MCC_WRB_EMBEDDED_MASK;
+ else
+ wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) <<
+ MCC_WRB_SGE_CNT_SHIFT;
+ wrb->payload_length = payload_len;
+ be_dws_cpu_to_le(wrb, 8);
+}
+
+void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
+ u8 subsystem, u8 opcode, int cmd_len)
+{
+ req_hdr->opcode = opcode;
+ req_hdr->subsystem = subsystem;
+ req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
+}
+
+static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages,
+ struct be_dma_mem *mem)
+{
+ int i, buf_pages;
+ u64 dma = (u64) mem->dma;
+
+ buf_pages = min(PAGES_4K_SPANNED(mem->va, mem->size), max_pages);
+ for (i = 0; i < buf_pages; i++) {
+ pages[i].lo = cpu_to_le32(dma & 0xFFFFFFFF);
+ pages[i].hi = cpu_to_le32(upper_32_bits(dma));
+ dma += PAGE_SIZE_4K;
+ }
+}
+
+static u32 eq_delay_to_mult(u32 usec_delay)
+{
+#define MAX_INTR_RATE 651042
+ const u32 round = 10;
+ u32 multiplier;
+
+ if (usec_delay == 0)
+ multiplier = 0;
+ else {
+ u32 interrupt_rate = 1000000 / usec_delay;
+ if (interrupt_rate == 0)
+ multiplier = 1023;
+ else {
+ multiplier = (MAX_INTR_RATE - interrupt_rate) * round;
+ multiplier /= interrupt_rate;
+ multiplier = (multiplier + round / 2) / round;
+ multiplier = min(multiplier, (u32) 1023);
+ }
+ }
+ return multiplier;
+}
+
+struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem)
+{
+ return &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb;
+}
+
+int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
+ struct be_queue_info *eq, int eq_delay)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_cmd_req_eq_create *req = embedded_payload(wrb);
+ struct be_cmd_resp_eq_create *resp = embedded_payload(wrb);
+ struct be_dma_mem *q_mem = &eq->dma_mem;
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_EQ_CREATE, sizeof(*req));
+
+ req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+
+ AMAP_SET_BITS(struct amap_eq_context, func, req->context,
+ PCI_FUNC(ctrl->pdev->devfn));
+ AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1);
+ AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0);
+ AMAP_SET_BITS(struct amap_eq_context, count, req->context,
+ __ilog2_u32(eq->len / 256));
+ AMAP_SET_BITS(struct amap_eq_context, delaymult, req->context,
+ eq_delay_to_mult(eq_delay));
+ be_dws_cpu_to_le(req->context, sizeof(req->context));
+
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ eq->id = le16_to_cpu(resp->eq_id);
+ eq->created = true;
+ }
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int be_cmd_fw_initialize(struct be_ctrl_info *ctrl)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ int status;
+ u8 *endian_check;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ endian_check = (u8 *) wrb;
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0x12;
+ *endian_check++ = 0x34;
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0xFF;
+ *endian_check++ = 0x56;
+ *endian_check++ = 0x78;
+ *endian_check++ = 0xFF;
+ be_dws_cpu_to_le(wrb, sizeof(*wrb));
+
+ status = be_mbox_notify(ctrl);
+ if (status)
+ SE_DEBUG(DBG_LVL_1, "be_cmd_fw_initialize Failed \n");
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
+ struct be_queue_info *cq, struct be_queue_info *eq,
+ bool sol_evts, bool no_delay, int coalesce_wm)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_cmd_req_cq_create *req = embedded_payload(wrb);
+ struct be_cmd_resp_cq_create *resp = embedded_payload(wrb);
+ struct be_dma_mem *q_mem = &cq->dma_mem;
+ void *ctxt = &req->context;
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_CQ_CREATE, sizeof(*req));
+
+ if (!q_mem->va)
+ SE_DEBUG(DBG_LVL_1, "uninitialized q_mem->va\n");
+
+ req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+
+ AMAP_SET_BITS(struct amap_cq_context, coalescwm, ctxt, coalesce_wm);
+ AMAP_SET_BITS(struct amap_cq_context, nodelay, ctxt, no_delay);
+ AMAP_SET_BITS(struct amap_cq_context, count, ctxt,
+ __ilog2_u32(cq->len / 256));
+ AMAP_SET_BITS(struct amap_cq_context, valid, ctxt, 1);
+ AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts);
+ AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1);
+ AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id);
+ AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1);
+ AMAP_SET_BITS(struct amap_cq_context, func, ctxt,
+ PCI_FUNC(ctrl->pdev->devfn));
+ be_dws_cpu_to_le(ctxt, sizeof(req->context));
+
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ cq->id = le16_to_cpu(resp->cq_id);
+ cq->created = true;
+ } else
+ SE_DEBUG(DBG_LVL_1, "In be_cmd_cq_create, status=ox%08x \n",
+ status);
+ spin_unlock(&ctrl->mbox_lock);
+
+ return status;
+}
+
+static u32 be_encoded_q_len(int q_len)
+{
+ u32 len_encoded = fls(q_len); /* log2(len) + 1 */
+ if (len_encoded == 16)
+ len_encoded = 0;
+ return len_encoded;
+}
+int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
+ int queue_type)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_cmd_req_q_destroy *req = embedded_payload(wrb);
+ u8 subsys = 0, opcode = 0;
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ switch (queue_type) {
+ case QTYPE_EQ:
+ subsys = CMD_SUBSYSTEM_COMMON;
+ opcode = OPCODE_COMMON_EQ_DESTROY;
+ break;
+ case QTYPE_CQ:
+ subsys = CMD_SUBSYSTEM_COMMON;
+ opcode = OPCODE_COMMON_CQ_DESTROY;
+ break;
+ case QTYPE_WRBQ:
+ subsys = CMD_SUBSYSTEM_ISCSI;
+ opcode = OPCODE_COMMON_ISCSI_WRBQ_DESTROY;
+ break;
+ case QTYPE_DPDUQ:
+ subsys = CMD_SUBSYSTEM_ISCSI;
+ opcode = OPCODE_COMMON_ISCSI_DEFQ_DESTROY;
+ break;
+ case QTYPE_SGL:
+ subsys = CMD_SUBSYSTEM_ISCSI;
+ opcode = OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES;
+ break;
+ default:
+ spin_unlock(&ctrl->mbox_lock);
+ BUG();
+ return -1;
+ }
+ be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req));
+ if (queue_type != QTYPE_SGL)
+ req->id = cpu_to_le16(q->id);
+
+ status = be_mbox_notify(ctrl);
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int be_cmd_get_mac_addr(struct be_ctrl_info *ctrl, u8 *mac_addr)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_cmd_req_get_mac_addr *req = embedded_payload(wrb);
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG,
+ sizeof(*req));
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ struct be_cmd_resp_get_mac_addr *resp = embedded_payload(wrb);
+
+ memcpy(mac_addr, resp->mac_address, ETH_ALEN);
+ }
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
+ struct be_queue_info *cq,
+ struct be_queue_info *dq, int length,
+ int entry_size)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_defq_create_req *req = embedded_payload(wrb);
+ struct be_dma_mem *q_mem = &dq->dma_mem;
+ void *ctxt = &req->context;
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_DEFQ_CREATE, sizeof(*req));
+
+ req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, rx_pdid, ctxt, 0);
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, rx_pdid_valid, ctxt,
+ 1);
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, pci_func_id, ctxt,
+ PCI_FUNC(ctrl->pdev->devfn));
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, ring_size, ctxt,
+ be_encoded_q_len(length / sizeof(struct phys_addr)));
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, default_buffer_size,
+ ctxt, entry_size);
+ AMAP_SET_BITS(struct amap_be_default_pdu_context, cq_id_recv, ctxt,
+ cq->id);
+
+ be_dws_cpu_to_le(ctxt, sizeof(req->context));
+
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ struct be_defq_create_resp *resp = embedded_payload(wrb);
+
+ dq->id = le16_to_cpu(resp->id);
+ dq->created = true;
+ }
+ spin_unlock(&ctrl->mbox_lock);
+
+ return status;
+}
+
+int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
+ struct be_queue_info *wrbq)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_wrbq_create_req *req = embedded_payload(wrb);
+ struct be_wrbq_create_resp *resp = embedded_payload(wrb);
+ int status;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_WRBQ_CREATE, sizeof(*req));
+ req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+ be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+ status = be_mbox_notify(ctrl);
+ if (!status)
+ wrbq->id = le16_to_cpu(resp->cid);
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
+ struct be_dma_mem *q_mem,
+ u32 page_offset, u32 num_pages)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_post_sgl_pages_req *req = embedded_payload(wrb);
+ int status;
+ unsigned int curr_pages;
+ u32 internal_page_offset = 0;
+ u32 temp_num_pages = num_pages;
+
+ if (num_pages == 0xff)
+ num_pages = 1;
+
+ spin_lock(&ctrl->mbox_lock);
+ do {
+ memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_CFG_POST_SGL_PAGES,
+ sizeof(*req));
+ curr_pages = BE_NUMBER_OF_FIELD(struct be_post_sgl_pages_req,
+ pages);
+ req->num_pages = min(num_pages, curr_pages);
+ req->page_offset = page_offset;
+ be_cmd_page_addrs_prepare(req->pages, req->num_pages, q_mem);
+ q_mem->dma = q_mem->dma + (req->num_pages * PAGE_SIZE);
+ internal_page_offset += req->num_pages;
+ page_offset += req->num_pages;
+ num_pages -= req->num_pages;
+
+ if (temp_num_pages == 0xff)
+ req->num_pages = temp_num_pages;
+
+ status = be_mbox_notify(ctrl);
+ if (status) {
+ SE_DEBUG(DBG_LVL_1,
+ "FW CMD to map iscsi frags failed.\n");
+ goto error;
+ }
+ } while (num_pages > 0);
+error:
+ spin_unlock(&ctrl->mbox_lock);
+ if (status != 0)
+ beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL);
+ return status;
+}
diff --git a/drivers/scsi/be2iscsi/be_cmds.h b/drivers/scsi/be2iscsi/be_cmds.h
new file mode 100644
index 000000000000..c20d686cbb43
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_cmds.h
@@ -0,0 +1,877 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * 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. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+#ifndef BEISCSI_CMDS_H
+#define BEISCSI_CMDS_H
+
+/**
+ * The driver sends configuration and managements command requests to the
+ * firmware in the BE. These requests are communicated to the processor
+ * using Work Request Blocks (WRBs) submitted to the MCC-WRB ring or via one
+ * WRB inside a MAILBOX.
+ * The commands are serviced by the ARM processor in the BladeEngine's MPU.
+ */
+struct be_sge {
+ u32 pa_lo;
+ u32 pa_hi;
+ u32 len;
+};
+
+#define MCC_WRB_SGE_CNT_SHIFT 3 /* bits 3 - 7 of dword 0 */
+#define MCC_WRB_SGE_CNT_MASK 0x1F /* bits 3 - 7 of dword 0 */
+struct be_mcc_wrb {
+ u32 embedded; /* dword 0 */
+ u32 payload_length; /* dword 1 */
+ u32 tag0; /* dword 2 */
+ u32 tag1; /* dword 3 */
+ u32 rsvd; /* dword 4 */
+ union {
+ u8 embedded_payload[236]; /* used by embedded cmds */
+ struct be_sge sgl[19]; /* used by non-embedded cmds */
+ } payload;
+};
+
+#define CQE_FLAGS_VALID_MASK (1 << 31)
+#define CQE_FLAGS_ASYNC_MASK (1 << 30)
+
+/* Completion Status */
+#define MCC_STATUS_SUCCESS 0x0
+
+#define CQE_STATUS_COMPL_MASK 0xFFFF
+#define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */
+#define CQE_STATUS_EXTD_MASK 0xFFFF
+#define CQE_STATUS_EXTD_SHIFT 0 /* bits 0 - 15 */
+
+struct be_mcc_compl {
+ u32 status; /* dword 0 */
+ u32 tag0; /* dword 1 */
+ u32 tag1; /* dword 2 */
+ u32 flags; /* dword 3 */
+};
+
+/********* Mailbox door bell *************/
+/**
+ * Used for driver communication with the FW.
+ * The software must write this register twice to post any command. First,
+ * it writes the register with hi=1 and the upper bits of the physical address
+ * for the MAILBOX structure. Software must poll the ready bit until this
+ * is acknowledged. Then, sotware writes the register with hi=0 with the lower
+ * bits in the address. It must poll the ready bit until the command is
+ * complete. Upon completion, the MAILBOX will contain a valid completion
+ * queue entry.
+ */
+#define MPU_MAILBOX_DB_OFFSET 0x160
+#define MPU_MAILBOX_DB_RDY_MASK 0x1 /* bit 0 */
+#define MPU_MAILBOX_DB_HI_MASK 0x2 /* bit 1 */
+
+/********** MPU semphore ******************/
+#define MPU_EP_SEMAPHORE_OFFSET 0xac
+#define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF
+#define EP_SEMAPHORE_POST_ERR_MASK 0x1
+#define EP_SEMAPHORE_POST_ERR_SHIFT 31
+
+/********** MCC door bell ************/
+#define DB_MCCQ_OFFSET 0x140
+#define DB_MCCQ_RING_ID_MASK 0x7FF /* bits 0 - 10 */
+/* Number of entries posted */
+#define DB_MCCQ_NUM_POSTED_SHIFT 16 /* bits 16 - 29 */
+
+/* MPU semphore POST stage values */
+#define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */
+
+/**
+ * When the async bit of mcc_compl is set, the last 4 bytes of
+ * mcc_compl is interpreted as follows:
+ */
+#define ASYNC_TRAILER_EVENT_CODE_SHIFT 8 /* bits 8 - 15 */
+#define ASYNC_TRAILER_EVENT_CODE_MASK 0xFF
+#define ASYNC_EVENT_CODE_LINK_STATE 0x1
+struct be_async_event_trailer {
+ u32 code;
+};
+
+enum {
+ ASYNC_EVENT_LINK_DOWN = 0x0,
+ ASYNC_EVENT_LINK_UP = 0x1
+};
+
+/**
+ * When the event code of an async trailer is link-state, the mcc_compl
+ * must be interpreted as follows
+ */
+struct be_async_event_link_state {
+ u8 physical_port;
+ u8 port_link_status;
+ u8 port_duplex;
+ u8 port_speed;
+ u8 port_fault;
+ u8 rsvd0[7];
+ struct be_async_event_trailer trailer;
+} __packed;
+
+struct be_mcc_mailbox {
+ struct be_mcc_wrb wrb;
+ struct be_mcc_compl compl;
+};
+
+/* Type of subsystems supported by FW */
+#define CMD_SUBSYSTEM_COMMON 0x1
+#define CMD_SUBSYSTEM_ISCSI 0x2
+#define CMD_SUBSYSTEM_ETH 0x3
+#define CMD_SUBSYSTEM_ISCSI_INI 0x6
+#define CMD_COMMON_TCP_UPLOAD 0x1
+
+/**
+ * List of common opcodes subsystem CMD_SUBSYSTEM_COMMON
+ * These opcodes are unique for each subsystem defined above
+ */
+#define OPCODE_COMMON_CQ_CREATE 12
+#define OPCODE_COMMON_EQ_CREATE 13
+#define OPCODE_COMMON_MCC_CREATE 21
+#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES 32
+#define OPCODE_COMMON_GET_FW_VERSION 35
+#define OPCODE_COMMON_MODIFY_EQ_DELAY 41
+#define OPCODE_COMMON_FIRMWARE_CONFIG 42
+#define OPCODE_COMMON_MCC_DESTROY 53
+#define OPCODE_COMMON_CQ_DESTROY 54
+#define OPCODE_COMMON_EQ_DESTROY 55
+#define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58
+#define OPCODE_COMMON_FUNCTION_RESET 61
+
+/**
+ * LIST of opcodes that are common between Initiator and Target
+ * used by CMD_SUBSYSTEM_ISCSI
+ * These opcodes are unique for each subsystem defined above
+ */
+#define OPCODE_COMMON_ISCSI_CFG_POST_SGL_PAGES 2
+#define OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES 3
+#define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG 7
+#define OPCODE_COMMON_ISCSI_SET_FRAGNUM_BITS_FOR_SGL_CRA 61
+#define OPCODE_COMMON_ISCSI_DEFQ_CREATE 64
+#define OPCODE_COMMON_ISCSI_DEFQ_DESTROY 65
+#define OPCODE_COMMON_ISCSI_WRBQ_CREATE 66
+#define OPCODE_COMMON_ISCSI_WRBQ_DESTROY 67
+
+struct be_cmd_req_hdr {
+ u8 opcode; /* dword 0 */
+ u8 subsystem; /* dword 0 */
+ u8 port_number; /* dword 0 */
+ u8 domain; /* dword 0 */
+ u32 timeout; /* dword 1 */
+ u32 request_length; /* dword 2 */
+ u32 rsvd; /* dword 3 */
+};
+
+struct be_cmd_resp_hdr {
+ u32 info; /* dword 0 */
+ u32 status; /* dword 1 */
+ u32 response_length; /* dword 2 */
+ u32 actual_resp_len; /* dword 3 */
+};
+
+struct phys_addr {
+ u32 lo;
+ u32 hi;
+};
+
+/**************************
+ * BE Command definitions *
+ **************************/
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte - used to calculate offset/shift/mask of each field
+ */
+struct amap_eq_context {
+ u8 cidx[13]; /* dword 0 */
+ u8 rsvd0[3]; /* dword 0 */
+ u8 epidx[13]; /* dword 0 */
+ u8 valid; /* dword 0 */
+ u8 rsvd1; /* dword 0 */
+ u8 size; /* dword 0 */
+ u8 pidx[13]; /* dword 1 */
+ u8 rsvd2[3]; /* dword 1 */
+ u8 pd[10]; /* dword 1 */
+ u8 count[3]; /* dword 1 */
+ u8 solevent; /* dword 1 */
+ u8 stalled; /* dword 1 */
+ u8 armed; /* dword 1 */
+ u8 rsvd3[4]; /* dword 2 */
+ u8 func[8]; /* dword 2 */
+ u8 rsvd4; /* dword 2 */
+ u8 delaymult[10]; /* dword 2 */
+ u8 rsvd5[2]; /* dword 2 */
+ u8 phase[2]; /* dword 2 */
+ u8 nodelay; /* dword 2 */
+ u8 rsvd6[4]; /* dword 2 */
+ u8 rsvd7[32]; /* dword 3 */
+} __packed;
+
+struct be_cmd_req_eq_create {
+ struct be_cmd_req_hdr hdr; /* dw[4] */
+ u16 num_pages; /* sword */
+ u16 rsvd0; /* sword */
+ u8 context[sizeof(struct amap_eq_context) / 8]; /* dw[4] */
+ struct phys_addr pages[8];
+} __packed;
+
+struct be_cmd_resp_eq_create {
+ struct be_cmd_resp_hdr resp_hdr;
+ u16 eq_id; /* sword */
+ u16 rsvd0; /* sword */
+} __packed;
+
+struct mac_addr {
+ u16 size_of_struct;
+ u8 addr[ETH_ALEN];
+} __packed;
+
+struct be_cmd_req_mac_query {
+ struct be_cmd_req_hdr hdr;
+ u8 type;
+ u8 permanent;
+ u16 if_id;
+} __packed;
+
+struct be_cmd_resp_mac_query {
+ struct be_cmd_resp_hdr hdr;
+ struct mac_addr mac;
+};
+
+/******************** Create CQ ***************************/
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte - used to calculate offset/shift/mask of each field
+ */
+struct amap_cq_context {
+ u8 cidx[11]; /* dword 0 */
+ u8 rsvd0; /* dword 0 */
+ u8 coalescwm[2]; /* dword 0 */
+ u8 nodelay; /* dword 0 */
+ u8 epidx[11]; /* dword 0 */
+ u8 rsvd1; /* dword 0 */
+ u8 count[2]; /* dword 0 */
+ u8 valid; /* dword 0 */
+ u8 solevent; /* dword 0 */
+ u8 eventable; /* dword 0 */
+ u8 pidx[11]; /* dword 1 */
+ u8 rsvd2; /* dword 1 */
+ u8 pd[10]; /* dword 1 */
+ u8 eqid[8]; /* dword 1 */
+ u8 stalled; /* dword 1 */
+ u8 armed; /* dword 1 */
+ u8 rsvd3[4]; /* dword 2 */
+ u8 func[8]; /* dword 2 */
+ u8 rsvd4[20]; /* dword 2 */
+ u8 rsvd5[32]; /* dword 3 */
+} __packed;
+
+struct be_cmd_req_cq_create {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+ u16 rsvd0;
+ u8 context[sizeof(struct amap_cq_context) / 8];
+ struct phys_addr pages[4];
+} __packed;
+
+struct be_cmd_resp_cq_create {
+ struct be_cmd_resp_hdr hdr;
+ u16 cq_id;
+ u16 rsvd0;
+} __packed;
+
+/******************** Create MCCQ ***************************/
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte - used to calculate offset/shift/mask of each field
+ */
+struct amap_mcc_context {
+ u8 con_index[14];
+ u8 rsvd0[2];
+ u8 ring_size[4];
+ u8 fetch_wrb;
+ u8 fetch_r2t;
+ u8 cq_id[10];
+ u8 prod_index[14];
+ u8 fid[8];
+ u8 pdid[9];
+ u8 valid;
+ u8 rsvd1[32];
+ u8 rsvd2[32];
+} __packed;
+
+struct be_cmd_req_mcc_create {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+ u16 rsvd0;
+ u8 context[sizeof(struct amap_mcc_context) / 8];
+ struct phys_addr pages[8];
+} __packed;
+
+struct be_cmd_resp_mcc_create {
+ struct be_cmd_resp_hdr hdr;
+ u16 id;
+ u16 rsvd0;
+} __packed;
+
+/******************** Q Destroy ***************************/
+/* Type of Queue to be destroyed */
+enum {
+ QTYPE_EQ = 1,
+ QTYPE_CQ,
+ QTYPE_MCCQ,
+ QTYPE_WRBQ,
+ QTYPE_DPDUQ,
+ QTYPE_SGL
+};
+
+struct be_cmd_req_q_destroy {
+ struct be_cmd_req_hdr hdr;
+ u16 id;
+ u16 bypass_flush; /* valid only for rx q destroy */
+} __packed;
+
+struct macaddr {
+ u8 byte[ETH_ALEN];
+};
+
+struct be_cmd_req_mcast_mac_config {
+ struct be_cmd_req_hdr hdr;
+ u16 num_mac;
+ u8 promiscuous;
+ u8 interface_id;
+ struct macaddr mac[32];
+} __packed;
+
+static inline void *embedded_payload(struct be_mcc_wrb *wrb)
+{
+ return wrb->payload.embedded_payload;
+}
+
+static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb)
+{
+ return &wrb->payload.sgl[0];
+}
+
+/******************** Modify EQ Delay *******************/
+struct be_cmd_req_modify_eq_delay {
+ struct be_cmd_req_hdr hdr;
+ u32 num_eq;
+ struct {
+ u32 eq_id;
+ u32 phase;
+ u32 delay_multiplier;
+ } delay[8];
+} __packed;
+
+/******************** Get MAC ADDR *******************/
+
+#define ETH_ALEN 6
+
+
+struct be_cmd_req_get_mac_addr {
+ struct be_cmd_req_hdr hdr;
+ u32 nic_port_count;
+ u32 speed;
+ u32 max_speed;
+ u32 link_state;
+ u32 max_frame_size;
+ u16 size_of_structure;
+ u8 mac_address[ETH_ALEN];
+ u32 rsvd[23];
+};
+
+struct be_cmd_resp_get_mac_addr {
+ struct be_cmd_resp_hdr hdr;
+ u32 nic_port_count;
+ u32 speed;
+ u32 max_speed;
+ u32 link_state;
+ u32 max_frame_size;
+ u16 size_of_structure;
+ u8 mac_address[6];
+ u32 rsvd[23];
+};
+
+int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl,
+ struct be_queue_info *eq, int eq_delay);
+
+int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl,
+ struct be_queue_info *cq, struct be_queue_info *eq,
+ bool sol_evts, bool no_delay,
+ int num_cqe_dma_coalesce);
+
+int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
+ int type);
+int be_poll_mcc(struct be_ctrl_info *ctrl);
+unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl);
+int be_cmd_get_mac_addr(struct be_ctrl_info *ctrl, u8 *mac_addr);
+
+/*ISCSI Functuions */
+int be_cmd_fw_initialize(struct be_ctrl_info *ctrl);
+
+struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem);
+
+int be_mbox_notify(struct be_ctrl_info *ctrl);
+
+int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl,
+ struct be_queue_info *cq,
+ struct be_queue_info *dq, int length,
+ int entry_size);
+
+int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl,
+ struct be_dma_mem *q_mem, u32 page_offset,
+ u32 num_pages);
+
+int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem,
+ struct be_queue_info *wrbq);
+
+struct be_default_pdu_context {
+ u32 dw[4];
+} __packed;
+
+struct amap_be_default_pdu_context {
+ u8 dbuf_cindex[13]; /* dword 0 */
+ u8 rsvd0[3]; /* dword 0 */
+ u8 ring_size[4]; /* dword 0 */
+ u8 ring_state[4]; /* dword 0 */
+ u8 rsvd1[8]; /* dword 0 */
+ u8 dbuf_pindex[13]; /* dword 1 */
+ u8 rsvd2; /* dword 1 */
+ u8 pci_func_id[8]; /* dword 1 */
+ u8 rx_pdid[9]; /* dword 1 */
+ u8 rx_pdid_valid; /* dword 1 */
+ u8 default_buffer_size[16]; /* dword 2 */
+ u8 cq_id_recv[10]; /* dword 2 */
+ u8 rx_pdid_not_valid; /* dword 2 */
+ u8 rsvd3[5]; /* dword 2 */
+ u8 rsvd4[32]; /* dword 3 */
+} __packed;
+
+struct be_defq_create_req {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+ u8 ulp_num;
+ u8 rsvd0;
+ struct be_default_pdu_context context;
+ struct phys_addr pages[8];
+} __packed;
+
+struct be_defq_create_resp {
+ struct be_cmd_req_hdr hdr;
+ u16 id;
+ u16 rsvd0;
+} __packed;
+
+struct be_post_sgl_pages_req {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+ u16 page_offset;
+ u32 rsvd0;
+ struct phys_addr pages[26];
+ u32 rsvd1;
+} __packed;
+
+struct be_wrbq_create_req {
+ struct be_cmd_req_hdr hdr;
+ u16 num_pages;
+ u8 ulp_num;
+ u8 rsvd0;
+ struct phys_addr pages[8];
+} __packed;
+
+struct be_wrbq_create_resp {
+ struct be_cmd_resp_hdr resp_hdr;
+ u16 cid;
+ u16 rsvd0;
+} __packed;
+
+#define SOL_CID_MASK 0x0000FFC0
+#define SOL_CODE_MASK 0x0000003F
+#define SOL_WRB_INDEX_MASK 0x00FF0000
+#define SOL_CMD_WND_MASK 0xFF000000
+#define SOL_RES_CNT_MASK 0x7FFFFFFF
+#define SOL_EXP_CMD_SN_MASK 0xFFFFFFFF
+#define SOL_HW_STS_MASK 0x000000FF
+#define SOL_STS_MASK 0x0000FF00
+#define SOL_RESP_MASK 0x00FF0000
+#define SOL_FLAGS_MASK 0x7F000000
+#define SOL_S_MASK 0x80000000
+
+struct sol_cqe {
+ u32 dw[4];
+};
+
+struct amap_sol_cqe {
+ u8 hw_sts[8]; /* dword 0 */
+ u8 i_sts[8]; /* dword 0 */
+ u8 i_resp[8]; /* dword 0 */
+ u8 i_flags[7]; /* dword 0 */
+ u8 s; /* dword 0 */
+ u8 i_exp_cmd_sn[32]; /* dword 1 */
+ u8 code[6]; /* dword 2 */
+ u8 cid[10]; /* dword 2 */
+ u8 wrb_index[8]; /* dword 2 */
+ u8 i_cmd_wnd[8]; /* dword 2 */
+ u8 i_res_cnt[31]; /* dword 3 */
+ u8 valid; /* dword 3 */
+} __packed;
+
+
+/**
+ * Post WRB Queue Doorbell Register used by the host Storage
+ * stack to notify the
+ * controller of a posted Work Request Block
+ */
+#define DB_WRB_POST_CID_MASK 0x3FF /* bits 0 - 9 */
+#define DB_DEF_PDU_WRB_INDEX_MASK 0xFF /* bits 0 - 9 */
+
+#define DB_DEF_PDU_WRB_INDEX_SHIFT 16
+#define DB_DEF_PDU_NUM_POSTED_SHIFT 24
+
+struct fragnum_bits_for_sgl_cra_in {
+ struct be_cmd_req_hdr hdr;
+ u32 num_bits;
+} __packed;
+
+struct iscsi_cleanup_req {
+ struct be_cmd_req_hdr hdr;
+ u16 chute;
+ u8 hdr_ring_id;
+ u8 data_ring_id;
+
+} __packed;
+
+struct eq_delay {
+ u32 eq_id;
+ u32 phase;
+ u32 delay_multiplier;
+} __packed;
+
+struct be_eq_delay_params_in {
+ struct be_cmd_req_hdr hdr;
+ u32 num_eq;
+ struct eq_delay delay[8];
+} __packed;
+
+struct ip_address_format {
+ u16 size_of_structure;
+ u8 reserved;
+ u8 ip_type;
+ u8 ip_address[16];
+ u32 rsvd0;
+} __packed;
+
+struct tcp_connect_and_offload_in {
+ struct be_cmd_req_hdr hdr;
+ struct ip_address_format ip_address;
+ u16 tcp_port;
+ u16 cid;
+ u16 cq_id;
+ u16 defq_id;
+ struct phys_addr dataout_template_pa;
+ u16 hdr_ring_id;
+ u16 data_ring_id;
+ u8 do_offload;
+ u8 rsvd0[3];
+} __packed;
+
+struct tcp_connect_and_offload_out {
+ struct be_cmd_resp_hdr hdr;
+ u32 connection_handle;
+ u16 cid;
+ u16 rsvd0;
+
+} __packed;
+
+struct be_mcc_wrb_context {
+ struct MCC_WRB *wrb;
+ int *users_final_status;
+} __packed;
+
+#define DB_DEF_PDU_RING_ID_MASK 0x3FF /* bits 0 - 9 */
+#define DB_DEF_PDU_CQPROC_MASK 0x3FFF /* bits 0 - 9 */
+#define DB_DEF_PDU_REARM_SHIFT 14
+#define DB_DEF_PDU_EVENT_SHIFT 15
+#define DB_DEF_PDU_CQPROC_SHIFT 16
+
+struct dmsg_cqe {
+ u32 dw[4];
+} __packed;
+
+struct tcp_upload_params_in {
+ struct be_cmd_req_hdr hdr;
+ u16 id;
+ u16 upload_type;
+ u32 reset_seq;
+} __packed;
+
+struct tcp_upload_params_out {
+ u32 dw[32];
+} __packed;
+
+union tcp_upload_params {
+ struct tcp_upload_params_in request;
+ struct tcp_upload_params_out response;
+} __packed;
+
+struct be_ulp_fw_cfg {
+ u32 ulp_mode;
+ u32 etx_base;
+ u32 etx_count;
+ u32 sq_base;
+ u32 sq_count;
+ u32 rq_base;
+ u32 rq_count;
+ u32 dq_base;
+ u32 dq_count;
+ u32 lro_base;
+ u32 lro_count;
+ u32 icd_base;
+ u32 icd_count;
+};
+
+struct be_fw_cfg {
+ struct be_cmd_req_hdr hdr;
+ u32 be_config_number;
+ u32 asic_revision;
+ u32 phys_port;
+ u32 function_mode;
+ struct be_ulp_fw_cfg ulp[2];
+ u32 function_caps;
+} __packed;
+
+#define CMD_ISCSI_COMMAND_INVALIDATE 1
+#define ISCSI_OPCODE_SCSI_DATA_OUT 5
+#define OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD 70
+#define OPCODE_ISCSI_INI_DRIVER_OFFLOAD_SESSION 41
+#define OPCODE_COMMON_MODIFY_EQ_DELAY 41
+#define OPCODE_COMMON_ISCSI_CLEANUP 59
+#define OPCODE_COMMON_TCP_UPLOAD 56
+#define OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS 1
+/* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */
+#define CMD_ISCSI_CONNECTION_INVALIDATE 1
+#define CMD_ISCSI_CONNECTION_ISSUE_TCP_RST 2
+#define OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION 42
+
+#define INI_WR_CMD 1 /* Initiator write command */
+#define INI_TMF_CMD 2 /* Initiator TMF command */
+#define INI_NOPOUT_CMD 3 /* Initiator; Send a NOP-OUT */
+#define INI_RD_CMD 5 /* Initiator requesting to send
+ * a read command
+ */
+#define TGT_CTX_UPDT_CMD 7 /* Target context update */
+#define TGT_STS_CMD 8 /* Target R2T and other BHS
+ * where only the status number
+ * need to be updated
+ */
+#define TGT_DATAIN_CMD 9 /* Target Data-Ins in response
+ * to read command
+ */
+#define TGT_SOS_PDU 10 /* Target:standalone status
+ * response
+ */
+#define TGT_DM_CMD 11 /* Indicates that the bhs
+ * preparedby
+ * driver should not be touched
+ */
+/* --- CMD_CHUTE_TYPE --- */
+#define CMD_CONNECTION_CHUTE_0 1
+#define CMD_CONNECTION_CHUTE_1 2
+#define CMD_CONNECTION_CHUTE_2 3
+
+#define EQ_MAJOR_CODE_COMPLETION 0
+
+#define CMD_ISCSI_SESSION_DEL_CFG_FROM_FLASH 0
+#define CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH 1
+
+/* --- CONNECTION_UPLOAD_PARAMS --- */
+/* These parameters are used to define the type of upload desired. */
+#define CONNECTION_UPLOAD_GRACEFUL 1 /* Graceful upload */
+#define CONNECTION_UPLOAD_ABORT_RESET 2 /* Abortive upload with
+ * reset
+ */
+#define CONNECTION_UPLOAD_ABORT 3 /* Abortive upload without
+ * reset
+ */
+#define CONNECTION_UPLOAD_ABORT_WITH_SEQ 4 /* Abortive upload with reset,
+ * sequence number by driver */
+
+/* Returns byte size of given field with a structure. */
+
+/* Returns the number of items in the field array. */
+#define BE_NUMBER_OF_FIELD(_type_, _field_) \
+ (FIELD_SIZEOF(_type_, _field_)/sizeof((((_type_ *)0)->_field_[0])))\
+
+/**
+ * Different types of iSCSI completions to host driver for both initiator
+ * and taget mode
+ * of operation.
+ */
+#define SOL_CMD_COMPLETE 1 /* Solicited command completed
+ * normally
+ */
+#define SOL_CMD_KILLED_DATA_DIGEST_ERR 2 /* Solicited command got
+ * invalidated internally due
+ * to Data Digest error
+ */
+#define CXN_KILLED_PDU_SIZE_EXCEEDS_DSL 3 /* Connection got invalidated
+ * internally
+ * due to a recieved PDU
+ * size > DSL
+ */
+#define CXN_KILLED_BURST_LEN_MISMATCH 4 /* Connection got invalidated
+ * internally due ti received
+ * PDU sequence size >
+ * FBL/MBL.
+ */
+#define CXN_KILLED_AHS_RCVD 5 /* Connection got invalidated
+ * internally due to a recieved
+ * PDU Hdr that has
+ * AHS */
+#define CXN_KILLED_HDR_DIGEST_ERR 6 /* Connection got invalidated
+ * internally due to Hdr Digest
+ * error
+ */
+#define CXN_KILLED_UNKNOWN_HDR 7 /* Connection got invalidated
+ * internally
+ * due to a bad opcode in the
+ * pdu hdr
+ */
+#define CXN_KILLED_STALE_ITT_TTT_RCVD 8 /* Connection got invalidated
+ * internally due to a recieved
+ * ITT/TTT that does not belong
+ * to this Connection
+ */
+#define CXN_KILLED_INVALID_ITT_TTT_RCVD 9 /* Connection got invalidated
+ * internally due to recieved
+ * ITT/TTT value > Max
+ * Supported ITTs/TTTs
+ */
+#define CXN_KILLED_RST_RCVD 10 /* Connection got invalidated
+ * internally due to an
+ * incoming TCP RST
+ */
+#define CXN_KILLED_TIMED_OUT 11 /* Connection got invalidated
+ * internally due to timeout on
+ * tcp segment 12 retransmit
+ * attempts failed
+ */
+#define CXN_KILLED_RST_SENT 12 /* Connection got invalidated
+ * internally due to TCP RST
+ * sent by the Tx side
+ */
+#define CXN_KILLED_FIN_RCVD 13 /* Connection got invalidated
+ * internally due to an
+ * incoming TCP FIN.
+ */
+#define CXN_KILLED_BAD_UNSOL_PDU_RCVD 14 /* Connection got invalidated
+ * internally due to bad
+ * unsolicited PDU Unsolicited
+ * PDUs are PDUs with
+ * ITT=0xffffffff
+ */
+#define CXN_KILLED_BAD_WRB_INDEX_ERROR 15 /* Connection got invalidated
+ * internally due to bad WRB
+ * index.
+ */
+#define CXN_KILLED_OVER_RUN_RESIDUAL 16 /* Command got invalidated
+ * internally due to recived
+ * command has residual
+ * over run bytes.
+ */
+#define CXN_KILLED_UNDER_RUN_RESIDUAL 17 /* Command got invalidated
+ * internally due to recived
+ * command has residual under
+ * run bytes.
+ */
+#define CMD_KILLED_INVALID_STATSN_RCVD 18 /* Command got invalidated
+ * internally due to a recieved
+ * PDU has an invalid StatusSN
+ */
+#define CMD_KILLED_INVALID_R2T_RCVD 19 /* Command got invalidated
+ * internally due to a recieved
+ * an R2T with some invalid
+ * fields in it
+ */
+#define CMD_CXN_KILLED_LUN_INVALID 20 /* Command got invalidated
+ * internally due to received
+ * PDU has an invalid LUN.
+ */
+#define CMD_CXN_KILLED_ICD_INVALID 21 /* Command got invalidated
+ * internally due to the
+ * corresponding ICD not in a
+ * valid state
+ */
+#define CMD_CXN_KILLED_ITT_INVALID 22 /* Command got invalidated due
+ * to received PDU has an
+ * invalid ITT.
+ */
+#define CMD_CXN_KILLED_SEQ_OUTOFORDER 23 /* Command got invalidated due
+ * to received sequence buffer
+ * offset is out of order.
+ */
+#define CMD_CXN_KILLED_INVALID_DATASN_RCVD 24 /* Command got invalidated
+ * internally due to a
+ * recieved PDU has an invalid
+ * DataSN
+ */
+#define CXN_INVALIDATE_NOTIFY 25 /* Connection invalidation
+ * completion notify.
+ */
+#define CXN_INVALIDATE_INDEX_NOTIFY 26 /* Connection invalidation
+ * completion
+ * with data PDU index.
+ */
+#define CMD_INVALIDATED_NOTIFY 27 /* Command invalidation
+ * completionnotifify.
+ */
+#define UNSOL_HDR_NOTIFY 28 /* Unsolicited header notify.*/
+#define UNSOL_DATA_NOTIFY 29 /* Unsolicited data notify.*/
+#define UNSOL_DATA_DIGEST_ERROR_NOTIFY 30 /* Unsolicited data digest
+ * error notify.
+ */
+#define DRIVERMSG_NOTIFY 31 /* TCP acknowledge based
+ * notification.
+ */
+#define CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN 32 /* Connection got invalidated
+ * internally due to command
+ * and data are not on same
+ * connection.
+ */
+#define SOL_CMD_KILLED_DIF_ERR 33 /* Solicited command got
+ * invalidated internally due
+ * to DIF error
+ */
+#define CXN_KILLED_SYN_RCVD 34 /* Connection got invalidated
+ * internally due to incoming
+ * TCP SYN
+ */
+#define CXN_KILLED_IMM_DATA_RCVD 35 /* Connection got invalidated
+ * internally due to an
+ * incoming Unsolicited PDU
+ * that has immediate data on
+ * the cxn
+ */
+
+void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
+ bool embedded, u8 sge_cnt);
+
+void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
+ u8 subsystem, u8 opcode, int cmd_len);
+
+#endif /* !BEISCSI_CMDS_H */
diff --git a/drivers/scsi/be2iscsi/be_iscsi.c b/drivers/scsi/be2iscsi/be_iscsi.c
new file mode 100644
index 000000000000..2fd25442cfaf
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_iscsi.c
@@ -0,0 +1,638 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * 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. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+
+#include <scsi/libiscsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+
+#include "be_iscsi.h"
+
+extern struct iscsi_transport beiscsi_iscsi_transport;
+
+/**
+ * beiscsi_session_create - creates a new iscsi session
+ * @cmds_max: max commands supported
+ * @qdepth: max queue depth supported
+ * @initial_cmdsn: initial iscsi CMDSN
+ */
+struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
+ u16 cmds_max,
+ u16 qdepth,
+ u32 initial_cmdsn)
+{
+ struct Scsi_Host *shost;
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct iscsi_cls_session *cls_session;
+ struct beiscsi_hba *phba;
+ struct iscsi_session *sess;
+ struct beiscsi_session *beiscsi_sess;
+ struct beiscsi_io_task *io_task;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_session_create\n");
+
+ if (!ep) {
+ SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep \n");
+ return NULL;
+ }
+ beiscsi_ep = ep->dd_data;
+ phba = beiscsi_ep->phba;
+ shost = phba->shost;
+ if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) {
+ shost_printk(KERN_ERR, shost, "Cannot handle %d cmds."
+ "Max cmds per session supported is %d. Using %d. "
+ "\n", cmds_max,
+ beiscsi_ep->phba->params.wrbs_per_cxn,
+ beiscsi_ep->phba->params.wrbs_per_cxn);
+ cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn;
+ }
+
+ cls_session = iscsi_session_setup(&beiscsi_iscsi_transport,
+ shost, cmds_max,
+ sizeof(*beiscsi_sess),
+ sizeof(*io_task),
+ initial_cmdsn, ISCSI_MAX_TARGET);
+ if (!cls_session)
+ return NULL;
+ sess = cls_session->dd_data;
+ beiscsi_sess = sess->dd_data;
+ beiscsi_sess->bhs_pool = pci_pool_create("beiscsi_bhs_pool",
+ phba->pcidev,
+ sizeof(struct be_cmd_bhs),
+ 64, 0);
+ if (!beiscsi_sess->bhs_pool)
+ goto destroy_sess;
+
+ return cls_session;
+destroy_sess:
+ iscsi_session_teardown(cls_session);
+ return NULL;
+}
+
+/**
+ * beiscsi_session_destroy - destroys iscsi session
+ * @cls_session: pointer to iscsi cls session
+ *
+ * Destroys iSCSI session instance and releases
+ * resources allocated for it.
+ */
+void beiscsi_session_destroy(struct iscsi_cls_session *cls_session)
+{
+ struct iscsi_session *sess = cls_session->dd_data;
+ struct beiscsi_session *beiscsi_sess = sess->dd_data;
+
+ pci_pool_destroy(beiscsi_sess->bhs_pool);
+ iscsi_session_teardown(cls_session);
+}
+
+/**
+ * beiscsi_conn_create - create an instance of iscsi connection
+ * @cls_session: ptr to iscsi_cls_session
+ * @cid: iscsi cid
+ */
+struct iscsi_cls_conn *
+beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid)
+{
+ struct beiscsi_hba *phba;
+ struct Scsi_Host *shost;
+ struct iscsi_cls_conn *cls_conn;
+ struct beiscsi_conn *beiscsi_conn;
+ struct iscsi_conn *conn;
+ struct iscsi_session *sess;
+ struct beiscsi_session *beiscsi_sess;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_create ,cid"
+ "from iscsi layer=%d\n", cid);
+ shost = iscsi_session_to_shost(cls_session);
+ phba = iscsi_host_priv(shost);
+
+ cls_conn = iscsi_conn_setup(cls_session, sizeof(*beiscsi_conn), cid);
+ if (!cls_conn)
+ return NULL;
+
+ conn = cls_conn->dd_data;
+ beiscsi_conn = conn->dd_data;
+ beiscsi_conn->ep = NULL;
+ beiscsi_conn->phba = phba;
+ beiscsi_conn->conn = conn;
+ sess = cls_session->dd_data;
+ beiscsi_sess = sess->dd_data;
+ beiscsi_conn->beiscsi_sess = beiscsi_sess;
+ return cls_conn;
+}
+
+/**
+ * beiscsi_bindconn_cid - Bind the beiscsi_conn with phba connection table
+ * @beiscsi_conn: The pointer to beiscsi_conn structure
+ * @phba: The phba instance
+ * @cid: The cid to free
+ */
+static int beiscsi_bindconn_cid(struct beiscsi_hba *phba,
+ struct beiscsi_conn *beiscsi_conn,
+ unsigned int cid)
+{
+ if (phba->conn_table[cid]) {
+ SE_DEBUG(DBG_LVL_1,
+ "Connection table already occupied. Detected clash\n");
+ return -EINVAL;
+ } else {
+ SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn) \n",
+ cid, beiscsi_conn);
+ phba->conn_table[cid] = beiscsi_conn;
+ }
+ return 0;
+}
+
+/**
+ * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection
+ * @cls_session: pointer to iscsi cls session
+ * @cls_conn: pointer to iscsi cls conn
+ * @transport_fd: EP handle(64 bit)
+ *
+ * This function binds the TCP Conn with iSCSI Connection and Session.
+ */
+int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
+ struct iscsi_cls_conn *cls_conn,
+ u64 transport_fd, int is_leading)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct Scsi_Host *shost =
+ (struct Scsi_Host *)iscsi_session_to_shost(cls_session);
+ struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost);
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct iscsi_endpoint *ep;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_bind\n");
+ ep = iscsi_lookup_endpoint(transport_fd);
+ if (!ep)
+ return -EINVAL;
+
+ beiscsi_ep = ep->dd_data;
+
+ if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
+ return -EINVAL;
+
+ if (beiscsi_ep->phba != phba) {
+ SE_DEBUG(DBG_LVL_8,
+ "beiscsi_ep->hba=%p not equal to phba=%p \n",
+ beiscsi_ep->phba, phba);
+ return -EEXIST;
+ }
+
+ beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid;
+ beiscsi_conn->ep = beiscsi_ep;
+ beiscsi_ep->conn = beiscsi_conn;
+ SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d \n",
+ beiscsi_conn, conn, beiscsi_ep->ep_cid);
+ return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid);
+}
+
+/**
+ * beiscsi_conn_get_param - get the iscsi parameter
+ * @cls_conn: pointer to iscsi cls conn
+ * @param: parameter type identifier
+ * @buf: buffer pointer
+ *
+ * returns iscsi parameter
+ */
+int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf)
+{
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ int len = 0;
+
+ beiscsi_ep = beiscsi_conn->ep;
+ if (!beiscsi_ep) {
+ SE_DEBUG(DBG_LVL_1,
+ "In beiscsi_conn_get_param , no beiscsi_ep\n");
+ return -1;
+ }
+
+ switch (param) {
+ case ISCSI_PARAM_CONN_PORT:
+ len = sprintf(buf, "%hu\n", beiscsi_ep->dst_tcpport);
+ break;
+ case ISCSI_PARAM_CONN_ADDRESS:
+ if (beiscsi_ep->ip_type == BE2_IPV4)
+ len = sprintf(buf, "%pI4\n", &beiscsi_ep->dst_addr);
+ else
+ len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr);
+ break;
+ default:
+ return iscsi_conn_get_param(cls_conn, param, buf);
+ }
+ return len;
+}
+
+int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf, int buflen)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct iscsi_session *session = conn->session;
+ int ret;
+
+ ret = iscsi_set_param(cls_conn, param, buf, buflen);
+ if (ret)
+ return ret;
+ /*
+ * If userspace tried to set the value to higher than we can
+ * support override here.
+ */
+ switch (param) {
+ case ISCSI_PARAM_FIRST_BURST:
+ if (session->first_burst > 8192)
+ session->first_burst = 8192;
+ break;
+ case ISCSI_PARAM_MAX_RECV_DLENGTH:
+ if (conn->max_recv_dlength > 65536)
+ conn->max_recv_dlength = 65536;
+ break;
+ case ISCSI_PARAM_MAX_BURST:
+ if (session->first_burst > 262144)
+ session->first_burst = 262144;
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+/**
+ * beiscsi_get_host_param - get the iscsi parameter
+ * @shost: pointer to scsi_host structure
+ * @param: parameter type identifier
+ * @buf: buffer pointer
+ *
+ * returns host parameter
+ */
+int beiscsi_get_host_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf)
+{
+ struct beiscsi_hba *phba = (struct beiscsi_hba *)iscsi_host_priv(shost);
+ int len = 0;
+
+ switch (param) {
+ case ISCSI_HOST_PARAM_HWADDRESS:
+ be_cmd_get_mac_addr(&phba->ctrl, phba->mac_address);
+ len = sysfs_format_mac(buf, phba->mac_address, ETH_ALEN);
+ break;
+ default:
+ return iscsi_host_get_param(shost, param, buf);
+ }
+ return len;
+}
+
+/**
+ * beiscsi_conn_get_stats - get the iscsi stats
+ * @cls_conn: pointer to iscsi cls conn
+ * @stats: pointer to iscsi_stats structure
+ *
+ * returns iscsi stats
+ */
+void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn,
+ struct iscsi_stats *stats)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_stats\n");
+ stats->txdata_octets = conn->txdata_octets;
+ stats->rxdata_octets = conn->rxdata_octets;
+ stats->dataout_pdus = conn->dataout_pdus_cnt;
+ stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
+ stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
+ stats->datain_pdus = conn->datain_pdus_cnt;
+ stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
+ stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
+ stats->r2t_pdus = conn->r2t_pdus_cnt;
+ stats->digest_err = 0;
+ stats->timeout_err = 0;
+ stats->custom_length = 0;
+ strcpy(stats->custom[0].desc, "eh_abort_cnt");
+ stats->custom[0].value = conn->eh_abort_cnt;
+}
+
+/**
+ * beiscsi_set_params_for_offld - get the parameters for offload
+ * @beiscsi_conn: pointer to beiscsi_conn
+ * @params: pointer to offload_params structure
+ */
+static void beiscsi_set_params_for_offld(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_offload_params *params)
+{
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+ struct iscsi_session *session = conn->session;
+
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_burst_length,
+ params, session->max_burst);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params,
+ max_send_data_segment_length, params,
+ conn->max_xmit_dlength);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, first_burst_length,
+ params, session->first_burst);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, erl, params,
+ session->erl);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, dde, params,
+ conn->datadgst_en);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, hde, params,
+ conn->hdrdgst_en);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, ir2t, params,
+ session->initial_r2t_en);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, imd, params,
+ session->imm_data_en);
+ AMAP_SET_BITS(struct amap_beiscsi_offload_params, exp_statsn, params,
+ (conn->exp_statsn - 1));
+}
+
+/**
+ * beiscsi_conn_start - offload of session to chip
+ * @cls_conn: pointer to beiscsi_conn
+ */
+int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct beiscsi_offload_params params;
+ struct iscsi_session *session = conn->session;
+ struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+
+ memset(&params, 0, sizeof(struct beiscsi_offload_params));
+ beiscsi_ep = beiscsi_conn->ep;
+ if (!beiscsi_ep)
+ SE_DEBUG(DBG_LVL_1, "In beiscsi_conn_start , no beiscsi_ep\n");
+
+ free_mgmt_sgl_handle(phba, beiscsi_conn->plogin_sgl_handle);
+ beiscsi_conn->login_in_progress = 0;
+ beiscsi_set_params_for_offld(beiscsi_conn, &params);
+ beiscsi_offload_connection(beiscsi_conn, &params);
+ iscsi_conn_start(cls_conn);
+ return 0;
+}
+
+/**
+ * beiscsi_get_cid - Allocate a cid
+ * @phba: The phba instance
+ */
+static int beiscsi_get_cid(struct beiscsi_hba *phba)
+{
+ unsigned short cid = 0xFFFF;
+
+ if (!phba->avlbl_cids)
+ return cid;
+
+ cid = phba->cid_array[phba->cid_alloc++];
+ if (phba->cid_alloc == phba->params.cxns_per_ctrl)
+ phba->cid_alloc = 0;
+ phba->avlbl_cids--;
+ return cid;
+}
+
+/**
+ * beiscsi_open_conn - Ask FW to open a TCP connection
+ * @ep: endpoint to be used
+ * @src_addr: The source IP address
+ * @dst_addr: The Destination IP address
+ *
+ * Asks the FW to open a TCP connection
+ */
+static int beiscsi_open_conn(struct iscsi_endpoint *ep,
+ struct sockaddr *src_addr,
+ struct sockaddr *dst_addr, int non_blocking)
+{
+ struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
+ struct beiscsi_hba *phba = beiscsi_ep->phba;
+ int ret = -1;
+
+ beiscsi_ep->ep_cid = beiscsi_get_cid(phba);
+ if (beiscsi_ep->ep_cid == 0xFFFF) {
+ SE_DEBUG(DBG_LVL_1, "No free cid available\n");
+ return ret;
+ }
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d ",
+ beiscsi_ep->ep_cid);
+ phba->ep_array[beiscsi_ep->ep_cid] = ep;
+ if (beiscsi_ep->ep_cid >
+ (phba->fw_config.iscsi_cid_start + phba->params.cxns_per_ctrl)) {
+ SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
+ return ret;
+ }
+
+ beiscsi_ep->cid_vld = 0;
+ return mgmt_open_connection(phba, dst_addr, beiscsi_ep);
+}
+
+/**
+ * beiscsi_put_cid - Free the cid
+ * @phba: The phba for which the cid is being freed
+ * @cid: The cid to free
+ */
+static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid)
+{
+ phba->avlbl_cids++;
+ phba->cid_array[phba->cid_free++] = cid;
+ if (phba->cid_free == phba->params.cxns_per_ctrl)
+ phba->cid_free = 0;
+}
+
+/**
+ * beiscsi_free_ep - free endpoint
+ * @ep: pointer to iscsi endpoint structure
+ */
+static void beiscsi_free_ep(struct iscsi_endpoint *ep)
+{
+ struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
+ struct beiscsi_hba *phba = beiscsi_ep->phba;
+
+ beiscsi_put_cid(phba, beiscsi_ep->ep_cid);
+ beiscsi_ep->phba = NULL;
+ iscsi_destroy_endpoint(ep);
+}
+
+/**
+ * beiscsi_ep_connect - Ask chip to create TCP Conn
+ * @scsi_host: Pointer to scsi_host structure
+ * @dst_addr: The IP address of Target
+ * @non_blocking: blocking or non-blocking call
+ *
+ * This routines first asks chip to create a connection and then allocates an EP
+ */
+struct iscsi_endpoint *
+beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
+ int non_blocking)
+{
+ struct beiscsi_hba *phba;
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct iscsi_endpoint *ep;
+ int ret;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect \n");
+ if (shost)
+ phba = iscsi_host_priv(shost);
+ else {
+ ret = -ENXIO;
+ SE_DEBUG(DBG_LVL_1, "shost is NULL \n");
+ return ERR_PTR(ret);
+ }
+ ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint));
+ if (!ep) {
+ ret = -ENOMEM;
+ return ERR_PTR(ret);
+ }
+
+ beiscsi_ep = ep->dd_data;
+ beiscsi_ep->phba = phba;
+
+ if (beiscsi_open_conn(ep, NULL, dst_addr, non_blocking)) {
+ SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n");
+ ret = -ENOMEM;
+ goto free_ep;
+ }
+
+ return ep;
+
+free_ep:
+ beiscsi_free_ep(ep);
+ return ERR_PTR(ret);
+}
+
+/**
+ * beiscsi_ep_poll - Poll to see if connection is established
+ * @ep: endpoint to be used
+ * @timeout_ms: timeout specified in millisecs
+ *
+ * Poll to see if TCP connection established
+ */
+int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
+{
+ struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_poll\n");
+ if (beiscsi_ep->cid_vld == 1)
+ return 1;
+ else
+ return 0;
+}
+
+/**
+ * beiscsi_close_conn - Upload the connection
+ * @ep: The iscsi endpoint
+ * @flag: The type of connection closure
+ */
+static int beiscsi_close_conn(struct iscsi_endpoint *ep, int flag)
+{
+ int ret = 0;
+ struct beiscsi_endpoint *beiscsi_ep = ep->dd_data;
+ struct beiscsi_hba *phba = beiscsi_ep->phba;
+
+ if (MGMT_STATUS_SUCCESS !=
+ mgmt_upload_connection(phba, beiscsi_ep->ep_cid,
+ CONNECTION_UPLOAD_GRACEFUL)) {
+ SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x",
+ beiscsi_ep->ep_cid);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+/**
+ * beiscsi_ep_disconnect - Tears down the TCP connection
+ * @ep: endpoint to be used
+ *
+ * Tears down the TCP connection
+ */
+void beiscsi_ep_disconnect(struct iscsi_endpoint *ep)
+{
+ struct beiscsi_conn *beiscsi_conn;
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct beiscsi_hba *phba;
+ int flag = 0;
+
+ beiscsi_ep = ep->dd_data;
+ phba = beiscsi_ep->phba;
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect\n");
+
+ if (beiscsi_ep->conn) {
+ beiscsi_conn = beiscsi_ep->conn;
+ iscsi_suspend_queue(beiscsi_conn->conn);
+ beiscsi_close_conn(ep, flag);
+ }
+
+ beiscsi_free_ep(ep);
+}
+
+/**
+ * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table
+ * @phba: The phba instance
+ * @cid: The cid to free
+ */
+static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba,
+ unsigned int cid)
+{
+ if (phba->conn_table[cid])
+ phba->conn_table[cid] = NULL;
+ else {
+ SE_DEBUG(DBG_LVL_8, "Connection table Not occupied. \n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * beiscsi_conn_stop - Invalidate and stop the connection
+ * @cls_conn: pointer to get iscsi_conn
+ * @flag: The type of connection closure
+ */
+void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag)
+{
+ struct iscsi_conn *conn = cls_conn->dd_data;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_endpoint *beiscsi_ep;
+ struct iscsi_session *session = conn->session;
+ struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session);
+ struct beiscsi_hba *phba = iscsi_host_priv(shost);
+ unsigned int status;
+ unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH;
+
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop\n");
+ beiscsi_ep = beiscsi_conn->ep;
+ if (!beiscsi_ep) {
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_stop , no beiscsi_ep\n");
+ return;
+ }
+ status = mgmt_invalidate_connection(phba, beiscsi_ep,
+ beiscsi_ep->ep_cid, 1,
+ savecfg_flag);
+ if (status != MGMT_STATUS_SUCCESS) {
+ SE_DEBUG(DBG_LVL_1,
+ "mgmt_invalidate_connection Failed for cid=%d \n",
+ beiscsi_ep->ep_cid);
+ }
+ beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid);
+ iscsi_conn_stop(cls_conn, flag);
+}
diff --git a/drivers/scsi/be2iscsi/be_iscsi.h b/drivers/scsi/be2iscsi/be_iscsi.h
new file mode 100644
index 000000000000..f92ffc5349fb
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_iscsi.h
@@ -0,0 +1,75 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * 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. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+
+#ifndef _BE_ISCSI_
+#define _BE_ISCSI_
+
+#include "be_main.h"
+#include "be_mgmt.h"
+
+#define BE2_IPV4 0x1
+#define BE2_IPV6 0x10
+
+void beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_offload_params *params);
+
+void beiscsi_offload_iscsi(struct beiscsi_hba *phba, struct iscsi_conn *conn,
+ struct beiscsi_conn *beiscsi_conn,
+ unsigned int fw_handle);
+
+struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep,
+ uint16_t cmds_max,
+ uint16_t qdepth,
+ uint32_t initial_cmdsn);
+
+void beiscsi_session_destroy(struct iscsi_cls_session *cls_session);
+
+struct iscsi_cls_conn *beiscsi_conn_create(struct iscsi_cls_session
+ *cls_session, uint32_t cid);
+
+int beiscsi_conn_bind(struct iscsi_cls_session *cls_session,
+ struct iscsi_cls_conn *cls_conn,
+ uint64_t transport_fd, int is_leading);
+
+int beiscsi_conn_get_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf);
+
+int beiscsi_get_host_param(struct Scsi_Host *shost,
+ enum iscsi_host_param param, char *buf);
+
+int beiscsi_set_param(struct iscsi_cls_conn *cls_conn,
+ enum iscsi_param param, char *buf, int buflen);
+
+int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn);
+
+void beiscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag);
+
+struct iscsi_endpoint *beiscsi_ep_connect(struct Scsi_Host *shost,
+ struct sockaddr *dst_addr,
+ int non_blocking);
+
+int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms);
+
+void beiscsi_ep_disconnect(struct iscsi_endpoint *ep);
+
+void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn,
+ struct iscsi_stats *stats);
+
+#endif
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
new file mode 100644
index 000000000000..4f1aca346e38
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -0,0 +1,3390 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * 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. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+#include <linux/reboot.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/semaphore.h>
+
+#include <scsi/libiscsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi.h>
+#include "be_main.h"
+#include "be_iscsi.h"
+#include "be_mgmt.h"
+
+static unsigned int be_iopoll_budget = 10;
+static unsigned int be_max_phys_size = 64;
+static unsigned int enable_msix;
+
+MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
+MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
+MODULE_AUTHOR("ServerEngines Corporation");
+MODULE_LICENSE("GPL");
+module_param(be_iopoll_budget, int, 0);
+module_param(enable_msix, int, 0);
+module_param(be_max_phys_size, uint, S_IRUGO);
+MODULE_PARM_DESC(be_max_phys_size, "Maximum Size (In Kilobytes) of physically"
+ "contiguous memory that can be allocated."
+ "Range is 16 - 128");
+
+static int beiscsi_slave_configure(struct scsi_device *sdev)
+{
+ blk_queue_max_segment_size(sdev->request_queue, 65536);
+ return 0;
+}
+
+static struct scsi_host_template beiscsi_sht = {
+ .module = THIS_MODULE,
+ .name = "ServerEngines 10Gbe open-iscsi Initiator Driver",
+ .proc_name = DRV_NAME,
+ .queuecommand = iscsi_queuecommand,
+ .eh_abort_handler = iscsi_eh_abort,
+ .change_queue_depth = iscsi_change_queue_depth,
+ .slave_configure = beiscsi_slave_configure,
+ .target_alloc = iscsi_target_alloc,
+ .eh_device_reset_handler = iscsi_eh_device_reset,
+ .eh_target_reset_handler = iscsi_eh_target_reset,
+ .sg_tablesize = BEISCSI_SGLIST_ELEMENTS,
+ .can_queue = BE2_IO_DEPTH,
+ .this_id = -1,
+ .max_sectors = BEISCSI_MAX_SECTORS,
+ .cmd_per_lun = BEISCSI_CMD_PER_LUN,
+ .use_clustering = ENABLE_CLUSTERING,
+};
+static struct scsi_transport_template *beiscsi_scsi_transport;
+
+/*------------------- PCI Driver operations and data ----------------- */
+static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = {
+ { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) },
+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) },
+ { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
+
+static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
+{
+ struct beiscsi_hba *phba;
+ struct Scsi_Host *shost;
+
+ shost = iscsi_host_alloc(&beiscsi_sht, sizeof(*phba), 0);
+ if (!shost) {
+ dev_err(&pcidev->dev, "beiscsi_hba_alloc -"
+ "iscsi_host_alloc failed \n");
+ return NULL;
+ }
+ shost->dma_boundary = pcidev->dma_mask;
+ shost->max_id = BE2_MAX_SESSIONS;
+ shost->max_channel = 0;
+ shost->max_cmd_len = BEISCSI_MAX_CMD_LEN;
+ shost->max_lun = BEISCSI_NUM_MAX_LUN;
+ shost->transportt = beiscsi_scsi_transport;
+
+ phba = iscsi_host_priv(shost);
+ memset(phba, 0, sizeof(*phba));
+ phba->shost = shost;
+ phba->pcidev = pci_dev_get(pcidev);
+
+ if (iscsi_host_add(shost, &phba->pcidev->dev))
+ goto free_devices;
+ return phba;
+
+free_devices:
+ pci_dev_put(phba->pcidev);
+ iscsi_host_free(phba->shost);
+ return NULL;
+}
+
+static void beiscsi_unmap_pci_function(struct beiscsi_hba *phba)
+{
+ if (phba->csr_va) {
+ iounmap(phba->csr_va);
+ phba->csr_va = NULL;
+ }
+ if (phba->db_va) {
+ iounmap(phba->db_va);
+ phba->db_va = NULL;
+ }
+ if (phba->pci_va) {
+ iounmap(phba->pci_va);
+ phba->pci_va = NULL;
+ }
+}
+
+static int beiscsi_map_pci_bars(struct beiscsi_hba *phba,
+ struct pci_dev *pcidev)
+{
+ u8 __iomem *addr;
+
+ addr = ioremap_nocache(pci_resource_start(pcidev, 2),
+ pci_resource_len(pcidev, 2));
+ if (addr == NULL)
+ return -ENOMEM;
+ phba->ctrl.csr = addr;
+ phba->csr_va = addr;
+ phba->csr_pa.u.a64.address = pci_resource_start(pcidev, 2);
+
+ addr = ioremap_nocache(pci_resource_start(pcidev, 4), 128 * 1024);
+ if (addr == NULL)
+ goto pci_map_err;
+ phba->ctrl.db = addr;
+ phba->db_va = addr;
+ phba->db_pa.u.a64.address = pci_resource_start(pcidev, 4);
+
+ addr = ioremap_nocache(pci_resource_start(pcidev, 1),
+ pci_resource_len(pcidev, 1));
+ if (addr == NULL)
+ goto pci_map_err;
+ phba->ctrl.pcicfg = addr;
+ phba->pci_va = addr;
+ phba->pci_pa.u.a64.address = pci_resource_start(pcidev, 1);
+ return 0;
+
+pci_map_err:
+ beiscsi_unmap_pci_function(phba);
+ return -ENOMEM;
+}
+
+static int beiscsi_enable_pci(struct pci_dev *pcidev)
+{
+ int ret;
+
+ ret = pci_enable_device(pcidev);
+ if (ret) {
+ dev_err(&pcidev->dev, "beiscsi_enable_pci - enable device "
+ "failed. Returning -ENODEV\n");
+ return ret;
+ }
+
+ if (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64))) {
+ ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32));
+ if (ret) {
+ dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n");
+ pci_disable_device(pcidev);
+ return ret;
+ }
+ }
+ return 0;
+}
+
+static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_dma_mem *mbox_mem_alloc = &ctrl->mbox_mem_alloced;
+ struct be_dma_mem *mbox_mem_align = &ctrl->mbox_mem;
+ int status = 0;
+
+ ctrl->pdev = pdev;
+ status = beiscsi_map_pci_bars(phba, pdev);
+ if (status)
+ return status;
+
+ mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16;
+ mbox_mem_alloc->va = pci_alloc_consistent(pdev,
+ mbox_mem_alloc->size,
+ &mbox_mem_alloc->dma);
+ if (!mbox_mem_alloc->va) {
+ beiscsi_unmap_pci_function(phba);
+ status = -ENOMEM;
+ return status;
+ }
+
+ mbox_mem_align->size = sizeof(struct be_mcc_mailbox);
+ mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16);
+ mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
+ memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));
+ spin_lock_init(&ctrl->mbox_lock);
+ return status;
+}
+
+static void beiscsi_get_params(struct beiscsi_hba *phba)
+{
+ phba->params.ios_per_ctrl = BE2_IO_DEPTH;
+ phba->params.cxns_per_ctrl = BE2_MAX_SESSIONS;
+ phba->params.asyncpdus_per_ctrl = BE2_ASYNCPDUS;
+ phba->params.icds_per_ctrl = BE2_MAX_ICDS / 2;
+ phba->params.num_sge_per_io = BE2_SGE;
+ phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ;
+ phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ;
+ phba->params.eq_timer = 64;
+ phba->params.num_eq_entries =
+ (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) /
+ 512) + 1) * 512;
+ phba->params.num_eq_entries = (phba->params.num_eq_entries < 1024)
+ ? 1024 : phba->params.num_eq_entries;
+ SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d \n",
+ phba->params.num_eq_entries);
+ phba->params.num_cq_entries =
+ (((BE2_CMDS_PER_CXN * 2 + BE2_LOGOUTS + BE2_TMFS + BE2_ASYNCPDUS) /
+ 512) + 1) * 512;
+ SE_DEBUG(DBG_LVL_8,
+ "phba->params.num_cq_entries=%d BE2_CMDS_PER_CXN=%d"
+ "BE2_LOGOUTS=%d BE2_TMFS=%d BE2_ASYNCPDUS=%d \n",
+ phba->params.num_cq_entries, BE2_CMDS_PER_CXN,
+ BE2_LOGOUTS, BE2_TMFS, BE2_ASYNCPDUS);
+ phba->params.wrbs_per_cxn = 256;
+}
+
+static void hwi_ring_eq_db(struct beiscsi_hba *phba,
+ unsigned int id, unsigned int clr_interrupt,
+ unsigned int num_processed,
+ unsigned char rearm, unsigned char event)
+{
+ u32 val = 0;
+ val |= id & DB_EQ_RING_ID_MASK;
+ if (rearm)
+ val |= 1 << DB_EQ_REARM_SHIFT;
+ if (clr_interrupt)
+ val |= 1 << DB_EQ_CLR_SHIFT;
+ if (event)
+ val |= 1 << DB_EQ_EVNT_SHIFT;
+ val |= num_processed << DB_EQ_NUM_POPPED_SHIFT;
+ iowrite32(val, phba->db_va + DB_EQ_OFFSET);
+}
+
+/**
+ * be_isr - The isr routine of the driver.
+ * @irq: Not used
+ * @dev_id: Pointer to host adapter structure
+ */
+static irqreturn_t be_isr(int irq, void *dev_id)
+{
+ struct beiscsi_hba *phba;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_eq_entry *eqe = NULL;
+ struct be_queue_info *eq;
+ struct be_queue_info *cq;
+ unsigned long flags, index;
+ unsigned int num_eq_processed;
+ struct be_ctrl_info *ctrl;
+ int isr;
+
+ phba = dev_id;
+ if (!enable_msix) {
+ ctrl = &phba->ctrl;;
+ isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET +
+ (PCI_FUNC(ctrl->pdev->devfn) * CEV_ISR_SIZE));
+ if (!isr)
+ return IRQ_NONE;
+ }
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ eq = &phwi_context->be_eq.q;
+ cq = &phwi_context->be_cq;
+ index = 0;
+ eqe = queue_tail_node(eq);
+ if (!eqe)
+ SE_DEBUG(DBG_LVL_1, "eqe is NULL\n");
+
+ num_eq_processed = 0;
+ if (blk_iopoll_enabled) {
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ if (!blk_iopoll_sched_prep(&phba->iopoll))
+ blk_iopoll_sched(&phba->iopoll);
+
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ num_eq_processed++;
+ SE_DEBUG(DBG_LVL_8, "Valid EQE\n");
+ }
+ if (num_eq_processed) {
+ hwi_ring_eq_db(phba, eq->id, 0, num_eq_processed, 0, 1);
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
+ } else {
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+
+ if (((eqe->dw[offsetof(struct amap_eq_entry,
+ resource_id) / 32] &
+ EQE_RESID_MASK) >> 16) != cq->id) {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ phba->todo_mcc_cq = 1;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ } else {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ phba->todo_cq = 1;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ }
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ num_eq_processed++;
+ }
+ if (phba->todo_cq || phba->todo_mcc_cq)
+ queue_work(phba->wq, &phba->work_cqs);
+
+ if (num_eq_processed) {
+ hwi_ring_eq_db(phba, eq->id, 0, num_eq_processed, 1, 1);
+ return IRQ_HANDLED;
+ } else
+ return IRQ_NONE;
+ }
+}
+
+static int beiscsi_init_irqs(struct beiscsi_hba *phba)
+{
+ struct pci_dev *pcidev = phba->pcidev;
+ int ret;
+
+ ret = request_irq(pcidev->irq, be_isr, IRQF_SHARED, "beiscsi", phba);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_init_irqs-"
+ "Failed to register irq\\n");
+ return ret;
+ }
+ return 0;
+}
+
+static void hwi_ring_cq_db(struct beiscsi_hba *phba,
+ unsigned int id, unsigned int num_processed,
+ unsigned char rearm, unsigned char event)
+{
+ u32 val = 0;
+ val |= id & DB_CQ_RING_ID_MASK;
+ if (rearm)
+ val |= 1 << DB_CQ_REARM_SHIFT;
+ val |= num_processed << DB_CQ_NUM_POPPED_SHIFT;
+ iowrite32(val, phba->db_va + DB_CQ_OFFSET);
+}
+
+/*
+ * async pdus include
+ * a. unsolicited NOP-In (target initiated NOP-In)
+ * b. Async Messages
+ * c. Reject PDU
+ * d. Login response
+ * These headers arrive unprocessed by the EP firmware and iSCSI layer
+ * process them
+ */
+static unsigned int
+beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba,
+ unsigned short cid,
+ struct pdu_base *ppdu,
+ unsigned long pdu_len,
+ void *pbuffer, unsigned long buf_len)
+{
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+ struct iscsi_session *session = conn->session;
+
+ switch (ppdu->dw[offsetof(struct amap_pdu_base, opcode) / 32] &
+ PDUBASE_OPCODE_MASK) {
+ case ISCSI_OP_NOOP_IN:
+ pbuffer = NULL;
+ buf_len = 0;
+ break;
+ case ISCSI_OP_ASYNC_EVENT:
+ break;
+ case ISCSI_OP_REJECT:
+ WARN_ON(!pbuffer);
+ WARN_ON(!(buf_len == 48));
+ SE_DEBUG(DBG_LVL_1, "In ISCSI_OP_REJECT\n");
+ break;
+ case ISCSI_OP_LOGIN_RSP:
+ break;
+ default:
+ shost_printk(KERN_WARNING, phba->shost,
+ "Unrecognized opcode 0x%x in async msg \n",
+ (ppdu->
+ dw[offsetof(struct amap_pdu_base, opcode) / 32]
+ & PDUBASE_OPCODE_MASK));
+ return 1;
+ }
+
+ spin_lock_bh(&session->lock);
+ __iscsi_complete_pdu(conn, (struct iscsi_hdr *)ppdu, pbuffer, buf_len);
+ spin_unlock_bh(&session->lock);
+ return 0;
+}
+
+static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba)
+{
+ struct sgl_handle *psgl_handle;
+
+ if (phba->io_sgl_hndl_avbl) {
+ SE_DEBUG(DBG_LVL_8,
+ "In alloc_io_sgl_handle,io_sgl_alloc_index=%d \n",
+ phba->io_sgl_alloc_index);
+ psgl_handle = phba->io_sgl_hndl_base[phba->
+ io_sgl_alloc_index];
+ phba->io_sgl_hndl_base[phba->io_sgl_alloc_index] = NULL;
+ phba->io_sgl_hndl_avbl--;
+ if (phba->io_sgl_alloc_index == (phba->params.ios_per_ctrl - 1))
+ phba->io_sgl_alloc_index = 0;
+ else
+ phba->io_sgl_alloc_index++;
+ } else
+ psgl_handle = NULL;
+ return psgl_handle;
+}
+
+static void
+free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
+{
+ SE_DEBUG(DBG_LVL_8, "In free_,io_sgl_free_index=%d \n",
+ phba->io_sgl_free_index);
+ if (phba->io_sgl_hndl_base[phba->io_sgl_free_index]) {
+ /*
+ * this can happen if clean_task is called on a task that
+ * failed in xmit_task or alloc_pdu.
+ */
+ SE_DEBUG(DBG_LVL_8,
+ "Double Free in IO SGL io_sgl_free_index=%d,"
+ "value there=%p \n", phba->io_sgl_free_index,
+ phba->io_sgl_hndl_base[phba->io_sgl_free_index]);
+ return;
+ }
+ phba->io_sgl_hndl_base[phba->io_sgl_free_index] = psgl_handle;
+ phba->io_sgl_hndl_avbl++;
+ if (phba->io_sgl_free_index == (phba->params.ios_per_ctrl - 1))
+ phba->io_sgl_free_index = 0;
+ else
+ phba->io_sgl_free_index++;
+}
+
+/**
+ * alloc_wrb_handle - To allocate a wrb handle
+ * @phba: The hba pointer
+ * @cid: The cid to use for allocation
+ * @index: index allocation and wrb index
+ *
+ * This happens under session_lock until submission to chip
+ */
+struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
+ int index)
+{
+ struct hwi_wrb_context *pwrb_context;
+ struct hwi_controller *phwi_ctrlr;
+ struct wrb_handle *pwrb_handle;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pwrb_context = &phwi_ctrlr->wrb_context[cid];
+ pwrb_handle = pwrb_context->pwrb_handle_base[index];
+ pwrb_handle->wrb_index = index;
+ pwrb_handle->nxt_wrb_index = index;
+ return pwrb_handle;
+}
+
+/**
+ * free_wrb_handle - To free the wrb handle back to pool
+ * @phba: The hba pointer
+ * @pwrb_context: The context to free from
+ * @pwrb_handle: The wrb_handle to free
+ *
+ * This happens under session_lock until submission to chip
+ */
+static void
+free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context,
+ struct wrb_handle *pwrb_handle)
+{
+ SE_DEBUG(DBG_LVL_8,
+ "FREE WRB: pwrb_handle=%p free_index=%d=0x%x"
+ "wrb_handles_available=%d \n",
+ pwrb_handle, pwrb_context->free_index,
+ pwrb_context->free_index, pwrb_context->wrb_handles_available);
+}
+
+static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba)
+{
+ struct sgl_handle *psgl_handle;
+
+ if (phba->eh_sgl_hndl_avbl) {
+ psgl_handle = phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index];
+ phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index] = NULL;
+ SE_DEBUG(DBG_LVL_8, "mgmt_sgl_alloc_index=%d=0x%x \n",
+ phba->eh_sgl_alloc_index, phba->eh_sgl_alloc_index);
+ phba->eh_sgl_hndl_avbl--;
+ if (phba->eh_sgl_alloc_index ==
+ (phba->params.icds_per_ctrl - phba->params.ios_per_ctrl -
+ 1))
+ phba->eh_sgl_alloc_index = 0;
+ else
+ phba->eh_sgl_alloc_index++;
+ } else
+ psgl_handle = NULL;
+ return psgl_handle;
+}
+
+void
+free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle)
+{
+
+ if (phba->eh_sgl_hndl_base[phba->eh_sgl_free_index]) {
+ /*
+ * this can happen if clean_task is called on a task that
+ * failed in xmit_task or alloc_pdu.
+ */
+ SE_DEBUG(DBG_LVL_8,
+ "Double Free in eh SGL ,eh_sgl_free_index=%d \n",
+ phba->eh_sgl_free_index);
+ return;
+ }
+ phba->eh_sgl_hndl_base[phba->eh_sgl_free_index] = psgl_handle;
+ phba->eh_sgl_hndl_avbl++;
+ if (phba->eh_sgl_free_index ==
+ (phba->params.icds_per_ctrl - phba->params.ios_per_ctrl - 1))
+ phba->eh_sgl_free_index = 0;
+ else
+ phba->eh_sgl_free_index++;
+}
+
+static void
+be_complete_io(struct beiscsi_conn *beiscsi_conn,
+ struct iscsi_task *task, struct sol_cqe *psol)
+{
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct be_status_bhs *sts_bhs =
+ (struct be_status_bhs *)io_task->cmd_bhs;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+ unsigned int sense_len;
+ unsigned char *sense;
+ u32 resid = 0, exp_cmdsn, max_cmdsn;
+ u8 rsp, status, flags;
+
+ exp_cmdsn = be32_to_cpu(psol->
+ dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
+ & SOL_EXP_CMD_SN_MASK);
+ max_cmdsn = be32_to_cpu((psol->
+ dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
+ & SOL_EXP_CMD_SN_MASK) +
+ ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
+ / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+ rsp = ((psol->dw[offsetof(struct amap_sol_cqe, i_resp) / 32]
+ & SOL_RESP_MASK) >> 16);
+ status = ((psol->dw[offsetof(struct amap_sol_cqe, i_sts) / 32]
+ & SOL_STS_MASK) >> 8);
+ flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
+ & SOL_FLAGS_MASK) >> 24) | 0x80;
+
+ task->sc->result = (DID_OK << 16) | status;
+ if (rsp != ISCSI_STATUS_CMD_COMPLETED) {
+ task->sc->result = DID_ERROR << 16;
+ goto unmap;
+ }
+
+ /* bidi not initially supported */
+ if (flags & (ISCSI_FLAG_CMD_UNDERFLOW | ISCSI_FLAG_CMD_OVERFLOW)) {
+ resid = (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) /
+ 32] & SOL_RES_CNT_MASK);
+
+ if (!status && (flags & ISCSI_FLAG_CMD_OVERFLOW))
+ task->sc->result = DID_ERROR << 16;
+
+ if (flags & ISCSI_FLAG_CMD_UNDERFLOW) {
+ scsi_set_resid(task->sc, resid);
+ if (!status && (scsi_bufflen(task->sc) - resid <
+ task->sc->underflow))
+ task->sc->result = DID_ERROR << 16;
+ }
+ }
+
+ if (status == SAM_STAT_CHECK_CONDITION) {
+ sense = sts_bhs->sense_info + sizeof(unsigned short);
+ sense_len =
+ cpu_to_be16((unsigned short)(sts_bhs->sense_info[0]));
+ memcpy(task->sc->sense_buffer, sense,
+ min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE));
+ }
+ if (io_task->cmd_bhs->iscsi_hdr.flags & ISCSI_FLAG_CMD_READ) {
+ if (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32]
+ & SOL_RES_CNT_MASK)
+ conn->rxdata_octets += (psol->
+ dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32]
+ & SOL_RES_CNT_MASK);
+ }
+unmap:
+ scsi_dma_unmap(io_task->scsi_cmnd);
+ iscsi_complete_scsi_task(task, exp_cmdsn, max_cmdsn);
+}
+
+static void
+be_complete_logout(struct beiscsi_conn *beiscsi_conn,
+ struct iscsi_task *task, struct sol_cqe *psol)
+{
+ struct iscsi_logout_rsp *hdr;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+
+ hdr = (struct iscsi_logout_rsp *)task->hdr;
+ hdr->t2wait = 5;
+ hdr->t2retain = 0;
+ hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
+ & SOL_FLAGS_MASK) >> 24) | 0x80;
+ hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) /
+ 32] & SOL_RESP_MASK);
+ hdr->exp_cmdsn = cpu_to_be32(psol->
+ dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
+ & SOL_EXP_CMD_SN_MASK);
+ hdr->max_cmdsn = be32_to_cpu((psol->
+ dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32]
+ & SOL_EXP_CMD_SN_MASK) +
+ ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
+ / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+ hdr->hlength = 0;
+
+ __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+}
+
+static void
+be_complete_tmf(struct beiscsi_conn *beiscsi_conn,
+ struct iscsi_task *task, struct sol_cqe *psol)
+{
+ struct iscsi_tm_rsp *hdr;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+
+ hdr = (struct iscsi_tm_rsp *)task->hdr;
+ hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
+ & SOL_FLAGS_MASK) >> 24) | 0x80;
+ hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) /
+ 32] & SOL_RESP_MASK);
+ hdr->exp_cmdsn = cpu_to_be32(psol->dw[offsetof(struct amap_sol_cqe,
+ i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK);
+ hdr->max_cmdsn = be32_to_cpu((psol->dw[offsetof(struct amap_sol_cqe,
+ i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK) +
+ ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
+ / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+ __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+}
+
+static void
+hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba, struct sol_cqe *psol)
+{
+ struct hwi_wrb_context *pwrb_context;
+ struct wrb_handle *pwrb_handle;
+ struct hwi_controller *phwi_ctrlr;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+ struct iscsi_session *session = conn->session;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pwrb_context = &phwi_ctrlr->wrb_context[((psol->
+ dw[offsetof(struct amap_sol_cqe, cid) / 32] &
+ SOL_CID_MASK) >> 6)];
+ pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
+ dw[offsetof(struct amap_sol_cqe, wrb_index) /
+ 32] & SOL_WRB_INDEX_MASK) >> 16)];
+ spin_lock_bh(&session->lock);
+ free_wrb_handle(phba, pwrb_context, pwrb_handle);
+ spin_unlock_bh(&session->lock);
+}
+
+static void
+be_complete_nopin_resp(struct beiscsi_conn *beiscsi_conn,
+ struct iscsi_task *task, struct sol_cqe *psol)
+{
+ struct iscsi_nopin *hdr;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+
+ hdr = (struct iscsi_nopin *)task->hdr;
+ hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32]
+ & SOL_FLAGS_MASK) >> 24) | 0x80;
+ hdr->exp_cmdsn = cpu_to_be32(psol->dw[offsetof(struct amap_sol_cqe,
+ i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK);
+ hdr->max_cmdsn = be32_to_cpu((psol->dw[offsetof(struct amap_sol_cqe,
+ i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK) +
+ ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd)
+ / 32] & SOL_CMD_WND_MASK) >> 24) - 1);
+ hdr->opcode = ISCSI_OP_NOOP_IN;
+ __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0);
+}
+
+static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba, struct sol_cqe *psol)
+{
+ struct hwi_wrb_context *pwrb_context;
+ struct wrb_handle *pwrb_handle;
+ struct iscsi_wrb *pwrb = NULL;
+ struct hwi_controller *phwi_ctrlr;
+ struct iscsi_task *task;
+ struct beiscsi_io_task *io_task;
+ struct iscsi_conn *conn = beiscsi_conn->conn;
+ struct iscsi_session *session = conn->session;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+
+ pwrb_context = &phwi_ctrlr->
+ wrb_context[((psol->dw[offsetof(struct amap_sol_cqe, cid) / 32]
+ & SOL_CID_MASK) >> 6)];
+ pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol->
+ dw[offsetof(struct amap_sol_cqe, wrb_index) /
+ 32] & SOL_WRB_INDEX_MASK) >> 16)];
+
+ task = pwrb_handle->pio_handle;
+ io_task = task->dd_data;
+ spin_lock_bh(&session->lock);
+ pwrb = pwrb_handle->pwrb;
+ switch ((pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] &
+ WRB_TYPE_MASK) >> 28) {
+ case HWH_TYPE_IO:
+ case HWH_TYPE_IO_RD:
+ if ((task->hdr->opcode & ISCSI_OPCODE_MASK) ==
+ ISCSI_OP_NOOP_OUT) {
+ be_complete_nopin_resp(beiscsi_conn, task, psol);
+ } else
+ be_complete_io(beiscsi_conn, task, psol);
+ break;
+
+ case HWH_TYPE_LOGOUT:
+ be_complete_logout(beiscsi_conn, task, psol);
+ break;
+
+ case HWH_TYPE_LOGIN:
+ SE_DEBUG(DBG_LVL_1,
+ "\t\t No HWH_TYPE_LOGIN Expected in hwi_complete_cmd"
+ "- Solicited path \n");
+ break;
+
+ case HWH_TYPE_TMF:
+ be_complete_tmf(beiscsi_conn, task, psol);
+ break;
+
+ case HWH_TYPE_NOP:
+ be_complete_nopin_resp(beiscsi_conn, task, psol);
+ break;
+
+ default:
+ shost_printk(KERN_WARNING, phba->shost,
+ "wrb_index 0x%x CID 0x%x\n",
+ ((psol->dw[offsetof(struct amap_iscsi_wrb, type) /
+ 32] & SOL_WRB_INDEX_MASK) >> 16),
+ ((psol->dw[offsetof(struct amap_sol_cqe, cid) / 32]
+ & SOL_CID_MASK) >> 6));
+ break;
+ }
+
+ spin_unlock_bh(&session->lock);
+}
+
+static struct list_head *hwi_get_async_busy_list(struct hwi_async_pdu_context
+ *pasync_ctx, unsigned int is_header,
+ unsigned int host_write_ptr)
+{
+ if (is_header)
+ return &pasync_ctx->async_entry[host_write_ptr].
+ header_busy_list;
+ else
+ return &pasync_ctx->async_entry[host_write_ptr].data_busy_list;
+}
+
+static struct async_pdu_handle *
+hwi_get_async_handle(struct beiscsi_hba *phba,
+ struct beiscsi_conn *beiscsi_conn,
+ struct hwi_async_pdu_context *pasync_ctx,
+ struct i_t_dpdu_cqe *pdpdu_cqe, unsigned int *pcq_index)
+{
+ struct be_bus_address phys_addr;
+ struct list_head *pbusy_list;
+ struct async_pdu_handle *pasync_handle = NULL;
+ int buffer_len = 0;
+ unsigned char buffer_index = -1;
+ unsigned char is_header = 0;
+
+ phys_addr.u.a32.address_lo =
+ pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, db_addr_lo) / 32] -
+ ((pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32]
+ & PDUCQE_DPL_MASK) >> 16);
+ phys_addr.u.a32.address_hi =
+ pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, db_addr_hi) / 32];
+
+ phys_addr.u.a64.address =
+ *((unsigned long long *)(&phys_addr.u.a64.address));
+
+ switch (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, code) / 32]
+ & PDUCQE_CODE_MASK) {
+ case UNSOL_HDR_NOTIFY:
+ is_header = 1;
+
+ pbusy_list = hwi_get_async_busy_list(pasync_ctx, 1,
+ (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
+ index) / 32] & PDUCQE_INDEX_MASK));
+
+ buffer_len = (unsigned int)(phys_addr.u.a64.address -
+ pasync_ctx->async_header.pa_base.u.a64.address);
+
+ buffer_index = buffer_len /
+ pasync_ctx->async_header.buffer_size;
+
+ break;
+ case UNSOL_DATA_NOTIFY:
+ pbusy_list = hwi_get_async_busy_list(pasync_ctx, 0, (pdpdu_cqe->
+ dw[offsetof(struct amap_i_t_dpdu_cqe,
+ index) / 32] & PDUCQE_INDEX_MASK));
+ buffer_len = (unsigned long)(phys_addr.u.a64.address -
+ pasync_ctx->async_data.pa_base.u.
+ a64.address);
+ buffer_index = buffer_len / pasync_ctx->async_data.buffer_size;
+ break;
+ default:
+ pbusy_list = NULL;
+ shost_printk(KERN_WARNING, phba->shost,
+ "Unexpected code=%d \n",
+ pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
+ code) / 32] & PDUCQE_CODE_MASK);
+ return NULL;
+ }
+
+ WARN_ON(!(buffer_index <= pasync_ctx->async_data.num_entries));
+ WARN_ON(list_empty(pbusy_list));
+ list_for_each_entry(pasync_handle, pbusy_list, link) {
+ WARN_ON(pasync_handle->consumed);
+ if (pasync_handle->index == buffer_index)
+ break;
+ }
+
+ WARN_ON(!pasync_handle);
+
+ pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid;
+ pasync_handle->is_header = is_header;
+ pasync_handle->buffer_len = ((pdpdu_cqe->
+ dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32]
+ & PDUCQE_DPL_MASK) >> 16);
+
+ *pcq_index = (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe,
+ index) / 32] & PDUCQE_INDEX_MASK);
+ return pasync_handle;
+}
+
+static unsigned int
+hwi_update_async_writables(struct hwi_async_pdu_context *pasync_ctx,
+ unsigned int is_header, unsigned int cq_index)
+{
+ struct list_head *pbusy_list;
+ struct async_pdu_handle *pasync_handle;
+ unsigned int num_entries, writables = 0;
+ unsigned int *pep_read_ptr, *pwritables;
+
+
+ if (is_header) {
+ pep_read_ptr = &pasync_ctx->async_header.ep_read_ptr;
+ pwritables = &pasync_ctx->async_header.writables;
+ num_entries = pasync_ctx->async_header.num_entries;
+ } else {
+ pep_read_ptr = &pasync_ctx->async_data.ep_read_ptr;
+ pwritables = &pasync_ctx->async_data.writables;
+ num_entries = pasync_ctx->async_data.num_entries;
+ }
+
+ while ((*pep_read_ptr) != cq_index) {
+ (*pep_read_ptr)++;
+ *pep_read_ptr = (*pep_read_ptr) % num_entries;
+
+ pbusy_list = hwi_get_async_busy_list(pasync_ctx, is_header,
+ *pep_read_ptr);
+ if (writables == 0)
+ WARN_ON(list_empty(pbusy_list));
+
+ if (!list_empty(pbusy_list)) {
+ pasync_handle = list_entry(pbusy_list->next,
+ struct async_pdu_handle,
+ link);
+ WARN_ON(!pasync_handle);
+ pasync_handle->consumed = 1;
+ }
+
+ writables++;
+ }
+
+ if (!writables) {
+ SE_DEBUG(DBG_LVL_1,
+ "Duplicate notification received - index 0x%x!!\n",
+ cq_index);
+ WARN_ON(1);
+ }
+
+ *pwritables = *pwritables + writables;
+ return 0;
+}
+
+static unsigned int hwi_free_async_msg(struct beiscsi_hba *phba,
+ unsigned int cri)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct async_pdu_handle *pasync_handle, *tmp_handle;
+ struct list_head *plist;
+ unsigned int i = 0;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+
+ plist = &pasync_ctx->async_entry[cri].wait_queue.list;
+
+ list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) {
+ list_del(&pasync_handle->link);
+
+ if (i == 0) {
+ list_add_tail(&pasync_handle->link,
+ &pasync_ctx->async_header.free_list);
+ pasync_ctx->async_header.free_entries++;
+ i++;
+ } else {
+ list_add_tail(&pasync_handle->link,
+ &pasync_ctx->async_data.free_list);
+ pasync_ctx->async_data.free_entries++;
+ i++;
+ }
+ }
+
+ INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wait_queue.list);
+ pasync_ctx->async_entry[cri].wait_queue.hdr_received = 0;
+ pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0;
+ return 0;
+}
+
+static struct phys_addr *
+hwi_get_ring_address(struct hwi_async_pdu_context *pasync_ctx,
+ unsigned int is_header, unsigned int host_write_ptr)
+{
+ struct phys_addr *pasync_sge = NULL;
+
+ if (is_header)
+ pasync_sge = pasync_ctx->async_header.ring_base;
+ else
+ pasync_sge = pasync_ctx->async_data.ring_base;
+
+ return pasync_sge + host_write_ptr;
+}
+
+static void hwi_post_async_buffers(struct beiscsi_hba *phba,
+ unsigned int is_header)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct async_pdu_handle *pasync_handle;
+ struct list_head *pfree_link, *pbusy_list;
+ struct phys_addr *pasync_sge;
+ unsigned int ring_id, num_entries;
+ unsigned int host_write_num;
+ unsigned int writables;
+ unsigned int i = 0;
+ u32 doorbell = 0;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+
+ if (is_header) {
+ num_entries = pasync_ctx->async_header.num_entries;
+ writables = min(pasync_ctx->async_header.writables,
+ pasync_ctx->async_header.free_entries);
+ pfree_link = pasync_ctx->async_header.free_list.next;
+ host_write_num = pasync_ctx->async_header.host_write_ptr;
+ ring_id = phwi_ctrlr->default_pdu_hdr.id;
+ } else {
+ num_entries = pasync_ctx->async_data.num_entries;
+ writables = min(pasync_ctx->async_data.writables,
+ pasync_ctx->async_data.free_entries);
+ pfree_link = pasync_ctx->async_data.free_list.next;
+ host_write_num = pasync_ctx->async_data.host_write_ptr;
+ ring_id = phwi_ctrlr->default_pdu_data.id;
+ }
+
+ writables = (writables / 8) * 8;
+ if (writables) {
+ for (i = 0; i < writables; i++) {
+ pbusy_list =
+ hwi_get_async_busy_list(pasync_ctx, is_header,
+ host_write_num);
+ pasync_handle =
+ list_entry(pfree_link, struct async_pdu_handle,
+ link);
+ WARN_ON(!pasync_handle);
+ pasync_handle->consumed = 0;
+
+ pfree_link = pfree_link->next;
+
+ pasync_sge = hwi_get_ring_address(pasync_ctx,
+ is_header, host_write_num);
+
+ pasync_sge->hi = pasync_handle->pa.u.a32.address_lo;
+ pasync_sge->lo = pasync_handle->pa.u.a32.address_hi;
+
+ list_move(&pasync_handle->link, pbusy_list);
+
+ host_write_num++;
+ host_write_num = host_write_num % num_entries;
+ }
+
+ if (is_header) {
+ pasync_ctx->async_header.host_write_ptr =
+ host_write_num;
+ pasync_ctx->async_header.free_entries -= writables;
+ pasync_ctx->async_header.writables -= writables;
+ pasync_ctx->async_header.busy_entries += writables;
+ } else {
+ pasync_ctx->async_data.host_write_ptr = host_write_num;
+ pasync_ctx->async_data.free_entries -= writables;
+ pasync_ctx->async_data.writables -= writables;
+ pasync_ctx->async_data.busy_entries += writables;
+ }
+
+ doorbell |= ring_id & DB_DEF_PDU_RING_ID_MASK;
+ doorbell |= 1 << DB_DEF_PDU_REARM_SHIFT;
+ doorbell |= 0 << DB_DEF_PDU_EVENT_SHIFT;
+ doorbell |= (writables & DB_DEF_PDU_CQPROC_MASK)
+ << DB_DEF_PDU_CQPROC_SHIFT;
+
+ iowrite32(doorbell, phba->db_va + DB_RXULP0_OFFSET);
+ }
+}
+
+static void hwi_flush_default_pdu_buffer(struct beiscsi_hba *phba,
+ struct beiscsi_conn *beiscsi_conn,
+ struct i_t_dpdu_cqe *pdpdu_cqe)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct async_pdu_handle *pasync_handle = NULL;
+ unsigned int cq_index = -1;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+
+ pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx,
+ pdpdu_cqe, &cq_index);
+ BUG_ON(pasync_handle->is_header != 0);
+ if (pasync_handle->consumed == 0)
+ hwi_update_async_writables(pasync_ctx, pasync_handle->is_header,
+ cq_index);
+
+ hwi_free_async_msg(phba, pasync_handle->cri);
+ hwi_post_async_buffers(phba, pasync_handle->is_header);
+}
+
+static unsigned int
+hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba,
+ struct hwi_async_pdu_context *pasync_ctx, unsigned short cri)
+{
+ struct list_head *plist;
+ struct async_pdu_handle *pasync_handle;
+ void *phdr = NULL;
+ unsigned int hdr_len = 0, buf_len = 0;
+ unsigned int status, index = 0, offset = 0;
+ void *pfirst_buffer = NULL;
+ unsigned int num_buf = 0;
+
+ plist = &pasync_ctx->async_entry[cri].wait_queue.list;
+
+ list_for_each_entry(pasync_handle, plist, link) {
+ if (index == 0) {
+ phdr = pasync_handle->pbuffer;
+ hdr_len = pasync_handle->buffer_len;
+ } else {
+ buf_len = pasync_handle->buffer_len;
+ if (!num_buf) {
+ pfirst_buffer = pasync_handle->pbuffer;
+ num_buf++;
+ }
+ memcpy(pfirst_buffer + offset,
+ pasync_handle->pbuffer, buf_len);
+ offset = buf_len;
+ }
+ index++;
+ }
+
+ status = beiscsi_process_async_pdu(beiscsi_conn, phba,
+ beiscsi_conn->beiscsi_conn_cid,
+ phdr, hdr_len, pfirst_buffer,
+ buf_len);
+
+ if (status == 0)
+ hwi_free_async_msg(phba, cri);
+ return 0;
+}
+
+static unsigned int
+hwi_gather_async_pdu(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba,
+ struct async_pdu_handle *pasync_handle)
+{
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct hwi_controller *phwi_ctrlr;
+ unsigned int bytes_needed = 0, status = 0;
+ unsigned short cri = pasync_handle->cri;
+ struct pdu_base *ppdu;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+
+ list_del(&pasync_handle->link);
+ if (pasync_handle->is_header) {
+ pasync_ctx->async_header.busy_entries--;
+ if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) {
+ hwi_free_async_msg(phba, cri);
+ BUG();
+ }
+
+ pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0;
+ pasync_ctx->async_entry[cri].wait_queue.hdr_received = 1;
+ pasync_ctx->async_entry[cri].wait_queue.hdr_len =
+ (unsigned short)pasync_handle->buffer_len;
+ list_add_tail(&pasync_handle->link,
+ &pasync_ctx->async_entry[cri].wait_queue.list);
+
+ ppdu = pasync_handle->pbuffer;
+ bytes_needed = ((((ppdu->dw[offsetof(struct amap_pdu_base,
+ data_len_hi) / 32] & PDUBASE_DATALENHI_MASK) << 8) &
+ 0xFFFF0000) | ((be16_to_cpu((ppdu->
+ dw[offsetof(struct amap_pdu_base, data_len_lo) / 32]
+ & PDUBASE_DATALENLO_MASK) >> 16)) & 0x0000FFFF));
+
+ if (status == 0) {
+ pasync_ctx->async_entry[cri].wait_queue.bytes_needed =
+ bytes_needed;
+
+ if (bytes_needed == 0)
+ status = hwi_fwd_async_msg(beiscsi_conn, phba,
+ pasync_ctx, cri);
+ }
+ } else {
+ pasync_ctx->async_data.busy_entries--;
+ if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) {
+ list_add_tail(&pasync_handle->link,
+ &pasync_ctx->async_entry[cri].wait_queue.
+ list);
+ pasync_ctx->async_entry[cri].wait_queue.
+ bytes_received +=
+ (unsigned short)pasync_handle->buffer_len;
+
+ if (pasync_ctx->async_entry[cri].wait_queue.
+ bytes_received >=
+ pasync_ctx->async_entry[cri].wait_queue.
+ bytes_needed)
+ status = hwi_fwd_async_msg(beiscsi_conn, phba,
+ pasync_ctx, cri);
+ }
+ }
+ return status;
+}
+
+static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba,
+ struct i_t_dpdu_cqe *pdpdu_cqe)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct async_pdu_handle *pasync_handle = NULL;
+ unsigned int cq_index = -1;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr);
+ pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx,
+ pdpdu_cqe, &cq_index);
+
+ if (pasync_handle->consumed == 0)
+ hwi_update_async_writables(pasync_ctx, pasync_handle->is_header,
+ cq_index);
+ hwi_gather_async_pdu(beiscsi_conn, phba, pasync_handle);
+ hwi_post_async_buffers(phba, pasync_handle->is_header);
+}
+
+static unsigned int beiscsi_process_cq(struct beiscsi_hba *phba)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_queue_info *cq;
+ struct sol_cqe *sol;
+ struct dmsg_cqe *dmsg;
+ unsigned int num_processed = 0;
+ unsigned int tot_nump = 0;
+ struct beiscsi_conn *beiscsi_conn;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ cq = &phwi_context->be_cq;
+ sol = queue_tail_node(cq);
+
+ while (sol->dw[offsetof(struct amap_sol_cqe, valid) / 32] &
+ CQE_VALID_MASK) {
+ be_dws_le_to_cpu(sol, sizeof(struct sol_cqe));
+
+ beiscsi_conn = phba->conn_table[(u32) (sol->
+ dw[offsetof(struct amap_sol_cqe, cid) / 32] &
+ SOL_CID_MASK) >> 6];
+
+ if (!beiscsi_conn || !beiscsi_conn->ep) {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Connection table empty for cid = %d\n",
+ (u32)(sol->dw[offsetof(struct amap_sol_cqe,
+ cid) / 32] & SOL_CID_MASK) >> 6);
+ return 0;
+ }
+
+ if (num_processed >= 32) {
+ hwi_ring_cq_db(phba, phwi_context->be_cq.id,
+ num_processed, 0, 0);
+ tot_nump += num_processed;
+ num_processed = 0;
+ }
+
+ switch ((u32) sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK) {
+ case SOL_CMD_COMPLETE:
+ hwi_complete_cmd(beiscsi_conn, phba, sol);
+ break;
+ case DRIVERMSG_NOTIFY:
+ SE_DEBUG(DBG_LVL_8, "Received DRIVERMSG_NOTIFY \n");
+ dmsg = (struct dmsg_cqe *)sol;
+ hwi_complete_drvr_msgs(beiscsi_conn, phba, sol);
+ break;
+ case UNSOL_HDR_NOTIFY:
+ case UNSOL_DATA_NOTIFY:
+ SE_DEBUG(DBG_LVL_8, "Received UNSOL_HDR/DATA_NOTIFY\n");
+ hwi_process_default_pdu_ring(beiscsi_conn, phba,
+ (struct i_t_dpdu_cqe *)sol);
+ break;
+ case CXN_INVALIDATE_INDEX_NOTIFY:
+ case CMD_INVALIDATED_NOTIFY:
+ case CXN_INVALIDATE_NOTIFY:
+ SE_DEBUG(DBG_LVL_1,
+ "Ignoring CQ Error notification for cmd/cxn"
+ "invalidate\n");
+ break;
+ case SOL_CMD_KILLED_DATA_DIGEST_ERR:
+ case CMD_KILLED_INVALID_STATSN_RCVD:
+ case CMD_KILLED_INVALID_R2T_RCVD:
+ case CMD_CXN_KILLED_LUN_INVALID:
+ case CMD_CXN_KILLED_ICD_INVALID:
+ case CMD_CXN_KILLED_ITT_INVALID:
+ case CMD_CXN_KILLED_SEQ_OUTOFORDER:
+ case CMD_CXN_KILLED_INVALID_DATASN_RCVD:
+ SE_DEBUG(DBG_LVL_1,
+ "CQ Error notification for cmd.. "
+ "code %d cid 0x%x\n",
+ sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK,
+ (sol->dw[offsetof(struct amap_sol_cqe, cid) /
+ 32] & SOL_CID_MASK));
+ break;
+ case UNSOL_DATA_DIGEST_ERROR_NOTIFY:
+ SE_DEBUG(DBG_LVL_1,
+ "Digest error on def pdu ring, dropping..\n");
+ hwi_flush_default_pdu_buffer(phba, beiscsi_conn,
+ (struct i_t_dpdu_cqe *) sol);
+ break;
+ case CXN_KILLED_PDU_SIZE_EXCEEDS_DSL:
+ case CXN_KILLED_BURST_LEN_MISMATCH:
+ case CXN_KILLED_AHS_RCVD:
+ case CXN_KILLED_HDR_DIGEST_ERR:
+ case CXN_KILLED_UNKNOWN_HDR:
+ case CXN_KILLED_STALE_ITT_TTT_RCVD:
+ case CXN_KILLED_INVALID_ITT_TTT_RCVD:
+ case CXN_KILLED_TIMED_OUT:
+ case CXN_KILLED_FIN_RCVD:
+ case CXN_KILLED_BAD_UNSOL_PDU_RCVD:
+ case CXN_KILLED_BAD_WRB_INDEX_ERROR:
+ case CXN_KILLED_OVER_RUN_RESIDUAL:
+ case CXN_KILLED_UNDER_RUN_RESIDUAL:
+ case CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN:
+ SE_DEBUG(DBG_LVL_1, "CQ Error %d, resetting CID "
+ "0x%x...\n",
+ sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK,
+ sol->dw[offsetof(struct amap_sol_cqe, cid) /
+ 32] & CQE_CID_MASK);
+ iscsi_conn_failure(beiscsi_conn->conn,
+ ISCSI_ERR_CONN_FAILED);
+ break;
+ case CXN_KILLED_RST_SENT:
+ case CXN_KILLED_RST_RCVD:
+ SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset received/sent "
+ "on CID 0x%x...\n",
+ sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK,
+ sol->dw[offsetof(struct amap_sol_cqe, cid) /
+ 32] & CQE_CID_MASK);
+ iscsi_conn_failure(beiscsi_conn->conn,
+ ISCSI_ERR_CONN_FAILED);
+ break;
+ default:
+ SE_DEBUG(DBG_LVL_1, "CQ Error Invalid code= %d "
+ "received on CID 0x%x...\n",
+ sol->dw[offsetof(struct amap_sol_cqe, code) /
+ 32] & CQE_CODE_MASK,
+ sol->dw[offsetof(struct amap_sol_cqe, cid) /
+ 32] & CQE_CID_MASK);
+ break;
+ }
+
+ AMAP_SET_BITS(struct amap_sol_cqe, valid, sol, 0);
+ queue_tail_inc(cq);
+ sol = queue_tail_node(cq);
+ num_processed++;
+ }
+
+ if (num_processed > 0) {
+ tot_nump += num_processed;
+ hwi_ring_cq_db(phba, phwi_context->be_cq.id, num_processed,
+ 1, 0);
+ }
+ return tot_nump;
+}
+
+static void beiscsi_process_all_cqs(struct work_struct *work)
+{
+ unsigned long flags;
+ struct beiscsi_hba *phba =
+ container_of(work, struct beiscsi_hba, work_cqs);
+
+ if (phba->todo_mcc_cq) {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ phba->todo_mcc_cq = 0;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ SE_DEBUG(DBG_LVL_1, "MCC Interrupt Not expected \n");
+ }
+
+ if (phba->todo_cq) {
+ spin_lock_irqsave(&phba->isr_lock, flags);
+ phba->todo_cq = 0;
+ spin_unlock_irqrestore(&phba->isr_lock, flags);
+ beiscsi_process_cq(phba);
+ }
+}
+
+static int be_iopoll(struct blk_iopoll *iop, int budget)
+{
+ static unsigned int ret;
+ struct beiscsi_hba *phba;
+
+ phba = container_of(iop, struct beiscsi_hba, iopoll);
+
+ ret = beiscsi_process_cq(phba);
+ if (ret < budget) {
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ blk_iopoll_complete(iop);
+ hwi_ring_eq_db(phba, phwi_context->be_eq.q.id, 0,
+ 0, 1, 1);
+ }
+ return ret;
+}
+
+static void
+hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg,
+ unsigned int num_sg, struct beiscsi_io_task *io_task)
+{
+ struct iscsi_sge *psgl;
+ unsigned short sg_len, index;
+ unsigned int sge_len = 0;
+ unsigned long long addr;
+ struct scatterlist *l_sg;
+ unsigned int offset;
+
+ AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_lo, pwrb,
+ io_task->bhs_pa.u.a32.address_lo);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_hi, pwrb,
+ io_task->bhs_pa.u.a32.address_hi);
+
+ l_sg = sg;
+ for (index = 0; (index < num_sg) && (index < 2); index++, sg_next(sg)) {
+ if (index == 0) {
+ sg_len = sg_dma_len(sg);
+ addr = (u64) sg_dma_address(sg);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb,
+ (addr & 0xFFFFFFFF));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb,
+ (addr >> 32));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb,
+ sg_len);
+ sge_len = sg_len;
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb,
+ 1);
+ } else {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb,
+ 0);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_r2t_offset,
+ pwrb, sge_len);
+ sg_len = sg_dma_len(sg);
+ addr = (u64) sg_dma_address(sg);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_lo, pwrb,
+ (addr & 0xFFFFFFFF));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_hi, pwrb,
+ (addr >> 32));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_len, pwrb,
+ sg_len);
+ }
+ }
+ psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag;
+ memset(psgl, 0, sizeof(*psgl) * BE2_SGE);
+
+ AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len - 2);
+
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
+ io_task->bhs_pa.u.a32.address_hi);
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
+ io_task->bhs_pa.u.a32.address_lo);
+
+ if (num_sg == 2)
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, 1);
+ sg = l_sg;
+ psgl++;
+ psgl++;
+ offset = 0;
+ for (index = 0; index < num_sg; index++, sg_next(sg), psgl++) {
+ sg_len = sg_dma_len(sg);
+ addr = (u64) sg_dma_address(sg);
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
+ (addr & 0xFFFFFFFF));
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
+ (addr >> 32));
+ AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, sg_len);
+ AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, offset);
+ AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0);
+ offset += sg_len;
+ }
+ psgl--;
+ AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1);
+}
+
+static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task)
+{
+ struct iscsi_sge *psgl;
+ unsigned long long addr;
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct beiscsi_conn *beiscsi_conn = io_task->conn;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+
+ io_task->bhs_len = sizeof(struct be_nonio_bhs) - 2;
+ AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_lo, pwrb,
+ io_task->bhs_pa.u.a32.address_lo);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_hi, pwrb,
+ io_task->bhs_pa.u.a32.address_hi);
+
+ if (task->data) {
+ if (task->data_count) {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1);
+ addr = (u64) pci_map_single(phba->pcidev,
+ task->data,
+ task->data_count, 1);
+ } else {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0);
+ addr = 0;
+ }
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb,
+ (addr & 0xFFFFFFFF));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb,
+ (addr >> 32));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb,
+ task->data_count);
+
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, 1);
+ } else {
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0);
+ addr = 0;
+ }
+
+ psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag;
+
+ AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len);
+
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
+ io_task->bhs_pa.u.a32.address_hi);
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
+ io_task->bhs_pa.u.a32.address_lo);
+ if (task->data) {
+ psgl++;
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, rsvd0, psgl, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0);
+
+ psgl++;
+ if (task->data) {
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl,
+ (addr & 0xFFFFFFFF));
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl,
+ (addr >> 32));
+ }
+ AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0x106);
+ }
+ AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1);
+}
+
+static void beiscsi_find_mem_req(struct beiscsi_hba *phba)
+{
+ unsigned int num_cq_pages, num_eq_pages, num_async_pdu_buf_pages;
+ unsigned int num_async_pdu_data_pages, wrb_sz_per_cxn;
+ unsigned int num_async_pdu_buf_sgl_pages, num_async_pdu_data_sgl_pages;
+
+ num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \
+ sizeof(struct sol_cqe));
+ num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries * \
+ sizeof(struct be_eq_entry));
+ num_async_pdu_buf_pages =
+ PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \
+ phba->params.defpdu_hdr_sz);
+ num_async_pdu_buf_sgl_pages =
+ PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \
+ sizeof(struct phys_addr));
+ num_async_pdu_data_pages =
+ PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \
+ phba->params.defpdu_data_sz);
+ num_async_pdu_data_sgl_pages =
+ PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \
+ sizeof(struct phys_addr));
+
+ phba->params.hwi_ws_sz = sizeof(struct hwi_controller);
+
+ phba->mem_req[ISCSI_MEM_GLOBAL_HEADER] = 2 *
+ BE_ISCSI_PDU_HEADER_SIZE;
+ phba->mem_req[HWI_MEM_ADDN_CONTEXT] =
+ sizeof(struct hwi_context_memory);
+
+ phba->mem_req[HWI_MEM_CQ] = num_cq_pages * PAGE_SIZE;
+ phba->mem_req[HWI_MEM_EQ] = num_eq_pages * PAGE_SIZE;
+
+ phba->mem_req[HWI_MEM_WRB] = sizeof(struct iscsi_wrb)
+ * (phba->params.wrbs_per_cxn)
+ * phba->params.cxns_per_ctrl;
+ wrb_sz_per_cxn = sizeof(struct wrb_handle) *
+ (phba->params.wrbs_per_cxn);
+ phba->mem_req[HWI_MEM_WRBH] = roundup_pow_of_two((wrb_sz_per_cxn) *
+ phba->params.cxns_per_ctrl);
+
+ phba->mem_req[HWI_MEM_SGLH] = sizeof(struct sgl_handle) *
+ phba->params.icds_per_ctrl;
+ phba->mem_req[HWI_MEM_SGE] = sizeof(struct iscsi_sge) *
+ phba->params.num_sge_per_io * phba->params.icds_per_ctrl;
+
+ phba->mem_req[HWI_MEM_ASYNC_HEADER_BUF] =
+ num_async_pdu_buf_pages * PAGE_SIZE;
+ phba->mem_req[HWI_MEM_ASYNC_DATA_BUF] =
+ num_async_pdu_data_pages * PAGE_SIZE;
+ phba->mem_req[HWI_MEM_ASYNC_HEADER_RING] =
+ num_async_pdu_buf_sgl_pages * PAGE_SIZE;
+ phba->mem_req[HWI_MEM_ASYNC_DATA_RING] =
+ num_async_pdu_data_sgl_pages * PAGE_SIZE;
+ phba->mem_req[HWI_MEM_ASYNC_HEADER_HANDLE] =
+ phba->params.asyncpdus_per_ctrl *
+ sizeof(struct async_pdu_handle);
+ phba->mem_req[HWI_MEM_ASYNC_DATA_HANDLE] =
+ phba->params.asyncpdus_per_ctrl *
+ sizeof(struct async_pdu_handle);
+ phba->mem_req[HWI_MEM_ASYNC_PDU_CONTEXT] =
+ sizeof(struct hwi_async_pdu_context) +
+ (phba->params.cxns_per_ctrl * sizeof(struct hwi_async_entry));
+}
+
+static int beiscsi_alloc_mem(struct beiscsi_hba *phba)
+{
+ struct be_mem_descriptor *mem_descr;
+ dma_addr_t bus_add;
+ struct mem_array *mem_arr, *mem_arr_orig;
+ unsigned int i, j, alloc_size, curr_alloc_size;
+
+ phba->phwi_ctrlr = kmalloc(phba->params.hwi_ws_sz, GFP_KERNEL);
+ if (!phba->phwi_ctrlr)
+ return -ENOMEM;
+
+ phba->init_mem = kcalloc(SE_MEM_MAX, sizeof(*mem_descr),
+ GFP_KERNEL);
+ if (!phba->init_mem) {
+ kfree(phba->phwi_ctrlr);
+ return -ENOMEM;
+ }
+
+ mem_arr_orig = kmalloc(sizeof(*mem_arr_orig) * BEISCSI_MAX_FRAGS_INIT,
+ GFP_KERNEL);
+ if (!mem_arr_orig) {
+ kfree(phba->init_mem);
+ kfree(phba->phwi_ctrlr);
+ return -ENOMEM;
+ }
+
+ mem_descr = phba->init_mem;
+ for (i = 0; i < SE_MEM_MAX; i++) {
+ j = 0;
+ mem_arr = mem_arr_orig;
+ alloc_size = phba->mem_req[i];
+ memset(mem_arr, 0, sizeof(struct mem_array) *
+ BEISCSI_MAX_FRAGS_INIT);
+ curr_alloc_size = min(be_max_phys_size * 1024, alloc_size);
+ do {
+ mem_arr->virtual_address = pci_alloc_consistent(
+ phba->pcidev,
+ curr_alloc_size,
+ &bus_add);
+ if (!mem_arr->virtual_address) {
+ if (curr_alloc_size <= BE_MIN_MEM_SIZE)
+ goto free_mem;
+ if (curr_alloc_size -
+ rounddown_pow_of_two(curr_alloc_size))
+ curr_alloc_size = rounddown_pow_of_two
+ (curr_alloc_size);
+ else
+ curr_alloc_size = curr_alloc_size / 2;
+ } else {
+ mem_arr->bus_address.u.
+ a64.address = (__u64) bus_add;
+ mem_arr->size = curr_alloc_size;
+ alloc_size -= curr_alloc_size;
+ curr_alloc_size = min(be_max_phys_size *
+ 1024, alloc_size);
+ j++;
+ mem_arr++;
+ }
+ } while (alloc_size);
+ mem_descr->num_elements = j;
+ mem_descr->size_in_bytes = phba->mem_req[i];
+ mem_descr->mem_array = kmalloc(sizeof(*mem_arr) * j,
+ GFP_KERNEL);
+ if (!mem_descr->mem_array)
+ goto free_mem;
+
+ memcpy(mem_descr->mem_array, mem_arr_orig,
+ sizeof(struct mem_array) * j);
+ mem_descr++;
+ }
+ kfree(mem_arr_orig);
+ return 0;
+free_mem:
+ mem_descr->num_elements = j;
+ while ((i) || (j)) {
+ for (j = mem_descr->num_elements; j > 0; j--) {
+ pci_free_consistent(phba->pcidev,
+ mem_descr->mem_array[j - 1].size,
+ mem_descr->mem_array[j - 1].
+ virtual_address,
+ mem_descr->mem_array[j - 1].
+ bus_address.u.a64.address);
+ }
+ if (i) {
+ i--;
+ kfree(mem_descr->mem_array);
+ mem_descr--;
+ }
+ }
+ kfree(mem_arr_orig);
+ kfree(phba->init_mem);
+ kfree(phba->phwi_ctrlr);
+ return -ENOMEM;
+}
+
+static int beiscsi_get_memory(struct beiscsi_hba *phba)
+{
+ beiscsi_find_mem_req(phba);
+ return beiscsi_alloc_mem(phba);
+}
+
+static void iscsi_init_global_templates(struct beiscsi_hba *phba)
+{
+ struct pdu_data_out *pdata_out;
+ struct pdu_nop_out *pnop_out;
+ struct be_mem_descriptor *mem_descr;
+
+ mem_descr = phba->init_mem;
+ mem_descr += ISCSI_MEM_GLOBAL_HEADER;
+ pdata_out =
+ (struct pdu_data_out *)mem_descr->mem_array[0].virtual_address;
+ memset(pdata_out, 0, BE_ISCSI_PDU_HEADER_SIZE);
+
+ AMAP_SET_BITS(struct amap_pdu_data_out, opcode, pdata_out,
+ IIOC_SCSI_DATA);
+
+ pnop_out =
+ (struct pdu_nop_out *)((unsigned char *)mem_descr->mem_array[0].
+ virtual_address + BE_ISCSI_PDU_HEADER_SIZE);
+
+ memset(pnop_out, 0, BE_ISCSI_PDU_HEADER_SIZE);
+ AMAP_SET_BITS(struct amap_pdu_nop_out, ttt, pnop_out, 0xFFFFFFFF);
+ AMAP_SET_BITS(struct amap_pdu_nop_out, f_bit, pnop_out, 1);
+ AMAP_SET_BITS(struct amap_pdu_nop_out, i_bit, pnop_out, 0);
+}
+
+static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba)
+{
+ struct be_mem_descriptor *mem_descr_wrbh, *mem_descr_wrb;
+ struct wrb_handle *pwrb_handle;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_wrb_context *pwrb_context;
+ struct iscsi_wrb *pwrb;
+ unsigned int num_cxn_wrbh;
+ unsigned int num_cxn_wrb, j, idx, index;
+
+ mem_descr_wrbh = phba->init_mem;
+ mem_descr_wrbh += HWI_MEM_WRBH;
+
+ mem_descr_wrb = phba->init_mem;
+ mem_descr_wrb += HWI_MEM_WRB;
+
+ idx = 0;
+ pwrb_handle = mem_descr_wrbh->mem_array[idx].virtual_address;
+ num_cxn_wrbh = ((mem_descr_wrbh->mem_array[idx].size) /
+ ((sizeof(struct wrb_handle)) *
+ phba->params.wrbs_per_cxn));
+ phwi_ctrlr = phba->phwi_ctrlr;
+
+ for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) {
+ pwrb_context = &phwi_ctrlr->wrb_context[index];
+ SE_DEBUG(DBG_LVL_8, "cid=%d pwrb_context=%p \n", index,
+ pwrb_context);
+ pwrb_context->pwrb_handle_base =
+ kzalloc(sizeof(struct wrb_handle *) *
+ phba->params.wrbs_per_cxn, GFP_KERNEL);
+ pwrb_context->pwrb_handle_basestd =
+ kzalloc(sizeof(struct wrb_handle *) *
+ phba->params.wrbs_per_cxn, GFP_KERNEL);
+ if (num_cxn_wrbh) {
+ pwrb_context->alloc_index = 0;
+ pwrb_context->wrb_handles_available = 0;
+ for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
+ pwrb_context->pwrb_handle_base[j] = pwrb_handle;
+ pwrb_context->pwrb_handle_basestd[j] =
+ pwrb_handle;
+ pwrb_context->wrb_handles_available++;
+ pwrb_handle++;
+ }
+ pwrb_context->free_index = 0;
+ num_cxn_wrbh--;
+ } else {
+ idx++;
+ pwrb_handle =
+ mem_descr_wrbh->mem_array[idx].virtual_address;
+ num_cxn_wrbh =
+ ((mem_descr_wrbh->mem_array[idx].size) /
+ ((sizeof(struct wrb_handle)) *
+ phba->params.wrbs_per_cxn));
+ pwrb_context->alloc_index = 0;
+ for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
+ pwrb_context->pwrb_handle_base[j] = pwrb_handle;
+ pwrb_context->pwrb_handle_basestd[j] =
+ pwrb_handle;
+ pwrb_context->wrb_handles_available++;
+ pwrb_handle++;
+ }
+ pwrb_context->free_index = 0;
+ num_cxn_wrbh--;
+ }
+ }
+ idx = 0;
+ pwrb = mem_descr_wrb->mem_array[idx].virtual_address;
+ num_cxn_wrb =
+ ((mem_descr_wrb->mem_array[idx].size) / (sizeof(struct iscsi_wrb)) *
+ phba->params.wrbs_per_cxn);
+
+ for (index = 0; index < phba->params.cxns_per_ctrl; index += 2) {
+ pwrb_context = &phwi_ctrlr->wrb_context[index];
+ if (num_cxn_wrb) {
+ for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
+ pwrb_handle = pwrb_context->pwrb_handle_base[j];
+ pwrb_handle->pwrb = pwrb;
+ pwrb++;
+ }
+ num_cxn_wrb--;
+ } else {
+ idx++;
+ pwrb = mem_descr_wrb->mem_array[idx].virtual_address;
+ num_cxn_wrb = ((mem_descr_wrb->mem_array[idx].size) /
+ (sizeof(struct iscsi_wrb)) *
+ phba->params.wrbs_per_cxn);
+ for (j = 0; j < phba->params.wrbs_per_cxn; j++) {
+ pwrb_handle = pwrb_context->pwrb_handle_base[j];
+ pwrb_handle->pwrb = pwrb;
+ pwrb++;
+ }
+ num_cxn_wrb--;
+ }
+ }
+}
+
+static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hba_parameters *p = &phba->params;
+ struct hwi_async_pdu_context *pasync_ctx;
+ struct async_pdu_handle *pasync_header_h, *pasync_data_h;
+ unsigned int index;
+ struct be_mem_descriptor *mem_descr;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_PDU_CONTEXT;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_ctrlr->phwi_ctxt->pasync_ctx = (struct hwi_async_pdu_context *)
+ mem_descr->mem_array[0].virtual_address;
+ pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx;
+ memset(pasync_ctx, 0, sizeof(*pasync_ctx));
+
+ pasync_ctx->async_header.num_entries = p->asyncpdus_per_ctrl;
+ pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz;
+ pasync_ctx->async_data.buffer_size = p->defpdu_data_sz;
+ pasync_ctx->async_data.num_entries = p->asyncpdus_per_ctrl;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_HEADER_BUF;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_BUF"
+ "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+
+ pasync_ctx->async_header.va_base =
+ mem_descr->mem_array[0].virtual_address;
+
+ pasync_ctx->async_header.pa_base.u.a64.address =
+ mem_descr->mem_array[0].bus_address.u.a64.address;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_HEADER_RING;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_RING"
+ "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+ pasync_ctx->async_header.ring_base =
+ mem_descr->mem_array[0].virtual_address;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_HEADER_HANDLE;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_HANDLE"
+ "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+
+ pasync_ctx->async_header.handle_base =
+ mem_descr->mem_array[0].virtual_address;
+ pasync_ctx->async_header.writables = 0;
+ INIT_LIST_HEAD(&pasync_ctx->async_header.free_list);
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_DATA_BUF;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF"
+ "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+ pasync_ctx->async_data.va_base =
+ mem_descr->mem_array[0].virtual_address;
+ pasync_ctx->async_data.pa_base.u.a64.address =
+ mem_descr->mem_array[0].bus_address.u.a64.address;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_DATA_RING;
+ if (mem_descr->mem_array[0].virtual_address) {
+ SE_DEBUG(DBG_LVL_8,
+ "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_RING"
+ "va=%p \n", mem_descr->mem_array[0].virtual_address);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+
+ pasync_ctx->async_data.ring_base =
+ mem_descr->mem_array[0].virtual_address;
+
+ mem_descr = (struct be_mem_descriptor *)phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_DATA_HANDLE;
+ if (!mem_descr->mem_array[0].virtual_address)
+ shost_printk(KERN_WARNING, phba->shost,
+ "No Virtual address \n");
+
+ pasync_ctx->async_data.handle_base =
+ mem_descr->mem_array[0].virtual_address;
+ pasync_ctx->async_data.writables = 0;
+ INIT_LIST_HEAD(&pasync_ctx->async_data.free_list);
+
+ pasync_header_h =
+ (struct async_pdu_handle *)pasync_ctx->async_header.handle_base;
+ pasync_data_h =
+ (struct async_pdu_handle *)pasync_ctx->async_data.handle_base;
+
+ for (index = 0; index < p->asyncpdus_per_ctrl; index++) {
+ pasync_header_h->cri = -1;
+ pasync_header_h->index = (char)index;
+ INIT_LIST_HEAD(&pasync_header_h->link);
+ pasync_header_h->pbuffer =
+ (void *)((unsigned long)
+ (pasync_ctx->async_header.va_base) +
+ (p->defpdu_hdr_sz * index));
+
+ pasync_header_h->pa.u.a64.address =
+ pasync_ctx->async_header.pa_base.u.a64.address +
+ (p->defpdu_hdr_sz * index);
+
+ list_add_tail(&pasync_header_h->link,
+ &pasync_ctx->async_header.free_list);
+ pasync_header_h++;
+ pasync_ctx->async_header.free_entries++;
+ pasync_ctx->async_header.writables++;
+
+ INIT_LIST_HEAD(&pasync_ctx->async_entry[index].wait_queue.list);
+ INIT_LIST_HEAD(&pasync_ctx->async_entry[index].
+ header_busy_list);
+ pasync_data_h->cri = -1;
+ pasync_data_h->index = (char)index;
+ INIT_LIST_HEAD(&pasync_data_h->link);
+ pasync_data_h->pbuffer =
+ (void *)((unsigned long)
+ (pasync_ctx->async_data.va_base) +
+ (p->defpdu_data_sz * index));
+
+ pasync_data_h->pa.u.a64.address =
+ pasync_ctx->async_data.pa_base.u.a64.address +
+ (p->defpdu_data_sz * index);
+
+ list_add_tail(&pasync_data_h->link,
+ &pasync_ctx->async_data.free_list);
+ pasync_data_h++;
+ pasync_ctx->async_data.free_entries++;
+ pasync_ctx->async_data.writables++;
+
+ INIT_LIST_HEAD(&pasync_ctx->async_entry[index].data_busy_list);
+ }
+
+ pasync_ctx->async_header.host_write_ptr = 0;
+ pasync_ctx->async_header.ep_read_ptr = -1;
+ pasync_ctx->async_data.host_write_ptr = 0;
+ pasync_ctx->async_data.ep_read_ptr = -1;
+}
+
+static int
+be_sgl_create_contiguous(void *virtual_address,
+ u64 physical_address, u32 length,
+ struct be_dma_mem *sgl)
+{
+ WARN_ON(!virtual_address);
+ WARN_ON(!physical_address);
+ WARN_ON(!length > 0);
+ WARN_ON(!sgl);
+
+ sgl->va = virtual_address;
+ sgl->dma = physical_address;
+ sgl->size = length;
+
+ return 0;
+}
+
+static void be_sgl_destroy_contiguous(struct be_dma_mem *sgl)
+{
+ memset(sgl, 0, sizeof(*sgl));
+}
+
+static void
+hwi_build_be_sgl_arr(struct beiscsi_hba *phba,
+ struct mem_array *pmem, struct be_dma_mem *sgl)
+{
+ if (sgl->va)
+ be_sgl_destroy_contiguous(sgl);
+
+ be_sgl_create_contiguous(pmem->virtual_address,
+ pmem->bus_address.u.a64.address,
+ pmem->size, sgl);
+}
+
+static void
+hwi_build_be_sgl_by_offset(struct beiscsi_hba *phba,
+ struct mem_array *pmem, struct be_dma_mem *sgl)
+{
+ if (sgl->va)
+ be_sgl_destroy_contiguous(sgl);
+
+ be_sgl_create_contiguous((unsigned char *)pmem->virtual_address,
+ pmem->bus_address.u.a64.address,
+ pmem->size, sgl);
+}
+
+static int be_fill_queue(struct be_queue_info *q,
+ u16 len, u16 entry_size, void *vaddress)
+{
+ struct be_dma_mem *mem = &q->dma_mem;
+
+ memset(q, 0, sizeof(*q));
+ q->len = len;
+ q->entry_size = entry_size;
+ mem->size = len * entry_size;
+ mem->va = vaddress;
+ if (!mem->va)
+ return -ENOMEM;
+ memset(mem->va, 0, mem->size);
+ return 0;
+}
+
+static int beiscsi_create_eq(struct beiscsi_hba *phba,
+ struct hwi_context_memory *phwi_context)
+{
+ unsigned int idx;
+ int ret;
+ struct be_queue_info *eq;
+ struct be_dma_mem *mem;
+ struct be_mem_descriptor *mem_descr;
+ void *eq_vaddress;
+
+ idx = 0;
+ eq = &phwi_context->be_eq.q;
+ mem = &eq->dma_mem;
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_EQ;
+ eq_vaddress = mem_descr->mem_array[idx].virtual_address;
+
+ ret = be_fill_queue(eq, phba->params.num_eq_entries,
+ sizeof(struct be_eq_entry), eq_vaddress);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_fill_queue Failed for EQ \n");
+ return ret;
+ }
+
+ mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+
+ ret = beiscsi_cmd_eq_create(&phba->ctrl, eq,
+ phwi_context->be_eq.cur_eqd);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_cmd_eq_create"
+ "Failedfor EQ \n");
+ return ret;
+ }
+ SE_DEBUG(DBG_LVL_8, "eq id is %d\n", phwi_context->be_eq.q.id);
+ return 0;
+}
+
+static int beiscsi_create_cq(struct beiscsi_hba *phba,
+ struct hwi_context_memory *phwi_context)
+{
+ unsigned int idx;
+ int ret;
+ struct be_queue_info *cq, *eq;
+ struct be_dma_mem *mem;
+ struct be_mem_descriptor *mem_descr;
+ void *cq_vaddress;
+
+ idx = 0;
+ cq = &phwi_context->be_cq;
+ eq = &phwi_context->be_eq.q;
+ mem = &cq->dma_mem;
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_CQ;
+ cq_vaddress = mem_descr->mem_array[idx].virtual_address;
+ ret = be_fill_queue(cq, phba->params.icds_per_ctrl / 2,
+ sizeof(struct sol_cqe), cq_vaddress);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_fill_queue Failed for ISCSI CQ \n");
+ return ret;
+ }
+
+ mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+ ret = beiscsi_cmd_cq_create(&phba->ctrl, cq, eq, false, false, 0);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "beiscsi_cmd_eq_create Failed for ISCSI CQ \n");
+ return ret;
+ }
+ SE_DEBUG(DBG_LVL_8, "iscsi cq id is %d\n", phwi_context->be_cq.id);
+ SE_DEBUG(DBG_LVL_8, "ISCSI CQ CREATED\n");
+ return 0;
+}
+
+static int
+beiscsi_create_def_hdr(struct beiscsi_hba *phba,
+ struct hwi_context_memory *phwi_context,
+ struct hwi_controller *phwi_ctrlr,
+ unsigned int def_pdu_ring_sz)
+{
+ unsigned int idx;
+ int ret;
+ struct be_queue_info *dq, *cq;
+ struct be_dma_mem *mem;
+ struct be_mem_descriptor *mem_descr;
+ void *dq_vaddress;
+
+ idx = 0;
+ dq = &phwi_context->be_def_hdrq;
+ cq = &phwi_context->be_cq;
+ mem = &dq->dma_mem;
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_HEADER_RING;
+ dq_vaddress = mem_descr->mem_array[idx].virtual_address;
+ ret = be_fill_queue(dq, mem_descr->mem_array[0].size /
+ sizeof(struct phys_addr),
+ sizeof(struct phys_addr), dq_vaddress);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_fill_queue Failed for DEF PDU HDR\n");
+ return ret;
+ }
+ mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+ ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dq,
+ def_pdu_ring_sz,
+ phba->params.defpdu_hdr_sz);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_cmd_create_default_pdu_queue Failed DEFHDR\n");
+ return ret;
+ }
+ phwi_ctrlr->default_pdu_hdr.id = phwi_context->be_def_hdrq.id;
+ SE_DEBUG(DBG_LVL_8, "iscsi def pdu id is %d\n",
+ phwi_context->be_def_hdrq.id);
+ hwi_post_async_buffers(phba, 1);
+ return 0;
+}
+
+static int
+beiscsi_create_def_data(struct beiscsi_hba *phba,
+ struct hwi_context_memory *phwi_context,
+ struct hwi_controller *phwi_ctrlr,
+ unsigned int def_pdu_ring_sz)
+{
+ unsigned int idx;
+ int ret;
+ struct be_queue_info *dataq, *cq;
+ struct be_dma_mem *mem;
+ struct be_mem_descriptor *mem_descr;
+ void *dq_vaddress;
+
+ idx = 0;
+ dataq = &phwi_context->be_def_dataq;
+ cq = &phwi_context->be_cq;
+ mem = &dataq->dma_mem;
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_ASYNC_DATA_RING;
+ dq_vaddress = mem_descr->mem_array[idx].virtual_address;
+ ret = be_fill_queue(dataq, mem_descr->mem_array[0].size /
+ sizeof(struct phys_addr),
+ sizeof(struct phys_addr), dq_vaddress);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_fill_queue Failed for DEF PDU DATA\n");
+ return ret;
+ }
+ mem->dma = mem_descr->mem_array[idx].bus_address.u.a64.address;
+ ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dataq,
+ def_pdu_ring_sz,
+ phba->params.defpdu_data_sz);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost,
+ "be_cmd_create_default_pdu_queue Failed"
+ " for DEF PDU DATA\n");
+ return ret;
+ }
+ phwi_ctrlr->default_pdu_data.id = phwi_context->be_def_dataq.id;
+ SE_DEBUG(DBG_LVL_8, "iscsi def data id is %d\n",
+ phwi_context->be_def_dataq.id);
+ hwi_post_async_buffers(phba, 0);
+ SE_DEBUG(DBG_LVL_8, "DEFAULT PDU DATA RING CREATED \n");
+ return 0;
+}
+
+static int
+beiscsi_post_pages(struct beiscsi_hba *phba)
+{
+ struct be_mem_descriptor *mem_descr;
+ struct mem_array *pm_arr;
+ unsigned int page_offset, i;
+ struct be_dma_mem sgl;
+ int status;
+
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_SGE;
+ pm_arr = mem_descr->mem_array;
+
+ page_offset = (sizeof(struct iscsi_sge) * phba->params.num_sge_per_io *
+ phba->fw_config.iscsi_icd_start) / PAGE_SIZE;
+ for (i = 0; i < mem_descr->num_elements; i++) {
+ hwi_build_be_sgl_arr(phba, pm_arr, &sgl);
+ status = be_cmd_iscsi_post_sgl_pages(&phba->ctrl, &sgl,
+ page_offset,
+ (pm_arr->size / PAGE_SIZE));
+ page_offset += pm_arr->size / PAGE_SIZE;
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "post sgl failed.\n");
+ return status;
+ }
+ pm_arr++;
+ }
+ SE_DEBUG(DBG_LVL_8, "POSTED PAGES \n");
+ return 0;
+}
+
+static int
+beiscsi_create_wrb_rings(struct beiscsi_hba *phba,
+ struct hwi_context_memory *phwi_context,
+ struct hwi_controller *phwi_ctrlr)
+{
+ unsigned int wrb_mem_index, offset, size, num_wrb_rings;
+ u64 pa_addr_lo;
+ unsigned int idx, num, i;
+ struct mem_array *pwrb_arr;
+ void *wrb_vaddr;
+ struct be_dma_mem sgl;
+ struct be_mem_descriptor *mem_descr;
+ int status;
+
+ idx = 0;
+ mem_descr = phba->init_mem;
+ mem_descr += HWI_MEM_WRB;
+ pwrb_arr = kmalloc(sizeof(*pwrb_arr) * phba->params.cxns_per_ctrl,
+ GFP_KERNEL);
+ if (!pwrb_arr) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Memory alloc failed in create wrb ring.\n");
+ return -ENOMEM;
+ }
+ wrb_vaddr = mem_descr->mem_array[idx].virtual_address;
+ pa_addr_lo = mem_descr->mem_array[idx].bus_address.u.a64.address;
+ num_wrb_rings = mem_descr->mem_array[idx].size /
+ (phba->params.wrbs_per_cxn * sizeof(struct iscsi_wrb));
+
+ for (num = 0; num < phba->params.cxns_per_ctrl; num++) {
+ if (num_wrb_rings) {
+ pwrb_arr[num].virtual_address = wrb_vaddr;
+ pwrb_arr[num].bus_address.u.a64.address = pa_addr_lo;
+ pwrb_arr[num].size = phba->params.wrbs_per_cxn *
+ sizeof(struct iscsi_wrb);
+ wrb_vaddr += pwrb_arr[num].size;
+ pa_addr_lo += pwrb_arr[num].size;
+ num_wrb_rings--;
+ } else {
+ idx++;
+ wrb_vaddr = mem_descr->mem_array[idx].virtual_address;
+ pa_addr_lo = mem_descr->mem_array[idx].\
+ bus_address.u.a64.address;
+ num_wrb_rings = mem_descr->mem_array[idx].size /
+ (phba->params.wrbs_per_cxn *
+ sizeof(struct iscsi_wrb));
+ pwrb_arr[num].virtual_address = wrb_vaddr;
+ pwrb_arr[num].bus_address.u.a64.address\
+ = pa_addr_lo;
+ pwrb_arr[num].size = phba->params.wrbs_per_cxn *
+ sizeof(struct iscsi_wrb);
+ wrb_vaddr += pwrb_arr[num].size;
+ pa_addr_lo += pwrb_arr[num].size;
+ num_wrb_rings--;
+ }
+ }
+ for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
+ wrb_mem_index = 0;
+ offset = 0;
+ size = 0;
+
+ hwi_build_be_sgl_by_offset(phba, &pwrb_arr[i], &sgl);
+ status = be_cmd_wrbq_create(&phba->ctrl, &sgl,
+ &phwi_context->be_wrbq[i]);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "wrbq create failed.");
+ return status;
+ }
+ phwi_ctrlr->wrb_context[i].cid = phwi_context->be_wrbq[i].id;
+ }
+ kfree(pwrb_arr);
+ return 0;
+}
+
+static void free_wrb_handles(struct beiscsi_hba *phba)
+{
+ unsigned int index;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_wrb_context *pwrb_context;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) {
+ pwrb_context = &phwi_ctrlr->wrb_context[index];
+ kfree(pwrb_context->pwrb_handle_base);
+ kfree(pwrb_context->pwrb_handle_basestd);
+ }
+}
+
+static void hwi_cleanup(struct beiscsi_hba *phba)
+{
+ struct be_queue_info *q;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ int i;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
+ q = &phwi_context->be_wrbq[i];
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ);
+ }
+
+ free_wrb_handles(phba);
+
+ q = &phwi_context->be_def_hdrq;
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
+
+ q = &phwi_context->be_def_dataq;
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ);
+
+ beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL);
+
+ q = &phwi_context->be_cq;
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ);
+
+ q = &phwi_context->be_eq.q;
+ if (q->created)
+ beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ);
+}
+
+static int hwi_init_port(struct beiscsi_hba *phba)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ unsigned int def_pdu_ring_sz;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ int status;
+
+ def_pdu_ring_sz =
+ phba->params.asyncpdus_per_ctrl * sizeof(struct phys_addr);
+ phwi_ctrlr = phba->phwi_ctrlr;
+
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ phwi_context->be_eq.max_eqd = 0;
+ phwi_context->be_eq.min_eqd = 0;
+ phwi_context->be_eq.cur_eqd = 64;
+ phwi_context->be_eq.enable_aic = false;
+ be_cmd_fw_initialize(&phba->ctrl);
+ status = beiscsi_create_eq(phba, phwi_context);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost, "EQ not created \n");
+ goto error;
+ }
+
+ status = mgmt_check_supported_fw(ctrl);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Unsupported fw version \n");
+ goto error;
+ }
+
+ status = mgmt_get_fw_config(ctrl, phba);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Error getting fw config\n");
+ goto error;
+ }
+
+ status = beiscsi_create_cq(phba, phwi_context);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost, "CQ not created\n");
+ goto error;
+ }
+
+ status = beiscsi_create_def_hdr(phba, phwi_context, phwi_ctrlr,
+ def_pdu_ring_sz);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Default Header not created\n");
+ goto error;
+ }
+
+ status = beiscsi_create_def_data(phba, phwi_context,
+ phwi_ctrlr, def_pdu_ring_sz);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Default Data not created\n");
+ goto error;
+ }
+
+ status = beiscsi_post_pages(phba);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost, "Post SGL Pages Failed\n");
+ goto error;
+ }
+
+ status = beiscsi_create_wrb_rings(phba, phwi_context, phwi_ctrlr);
+ if (status != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "WRB Rings not created\n");
+ goto error;
+ }
+
+ SE_DEBUG(DBG_LVL_8, "hwi_init_port success\n");
+ return 0;
+
+error:
+ shost_printk(KERN_ERR, phba->shost, "hwi_init_port failed");
+ hwi_cleanup(phba);
+ return -ENOMEM;
+}
+
+
+static int hwi_init_controller(struct beiscsi_hba *phba)
+{
+ struct hwi_controller *phwi_ctrlr;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ if (1 == phba->init_mem[HWI_MEM_ADDN_CONTEXT].num_elements) {
+ phwi_ctrlr->phwi_ctxt = (struct hwi_context_memory *)phba->
+ init_mem[HWI_MEM_ADDN_CONTEXT].mem_array[0].virtual_address;
+ SE_DEBUG(DBG_LVL_8, " phwi_ctrlr->phwi_ctxt=%p \n",
+ phwi_ctrlr->phwi_ctxt);
+ } else {
+ shost_printk(KERN_ERR, phba->shost,
+ "HWI_MEM_ADDN_CONTEXT is more than one element."
+ "Failing to load\n");
+ return -ENOMEM;
+ }
+
+ iscsi_init_global_templates(phba);
+ beiscsi_init_wrb_handle(phba);
+ hwi_init_async_pdu_ctx(phba);
+ if (hwi_init_port(phba) != 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "hwi_init_controller failed\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void beiscsi_free_mem(struct beiscsi_hba *phba)
+{
+ struct be_mem_descriptor *mem_descr;
+ int i, j;
+
+ mem_descr = phba->init_mem;
+ i = 0;
+ j = 0;
+ for (i = 0; i < SE_MEM_MAX; i++) {
+ for (j = mem_descr->num_elements; j > 0; j--) {
+ pci_free_consistent(phba->pcidev,
+ mem_descr->mem_array[j - 1].size,
+ mem_descr->mem_array[j - 1].virtual_address,
+ mem_descr->mem_array[j - 1].bus_address.
+ u.a64.address);
+ }
+ kfree(mem_descr->mem_array);
+ mem_descr++;
+ }
+ kfree(phba->init_mem);
+ kfree(phba->phwi_ctrlr);
+}
+
+static int beiscsi_init_controller(struct beiscsi_hba *phba)
+{
+ int ret = -ENOMEM;
+
+ ret = beiscsi_get_memory(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe -"
+ "Failed in beiscsi_alloc_memory \n");
+ return ret;
+ }
+
+ ret = hwi_init_controller(phba);
+ if (ret)
+ goto free_init;
+ SE_DEBUG(DBG_LVL_8, "Return success from beiscsi_init_controller");
+ return 0;
+
+free_init:
+ beiscsi_free_mem(phba);
+ return -ENOMEM;
+}
+
+static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba)
+{
+ struct be_mem_descriptor *mem_descr_sglh, *mem_descr_sg;
+ struct sgl_handle *psgl_handle;
+ struct iscsi_sge *pfrag;
+ unsigned int arr_index, i, idx;
+
+ phba->io_sgl_hndl_avbl = 0;
+ phba->eh_sgl_hndl_avbl = 0;
+ mem_descr_sglh = phba->init_mem;
+ mem_descr_sglh += HWI_MEM_SGLH;
+ if (1 == mem_descr_sglh->num_elements) {
+ phba->io_sgl_hndl_base = kzalloc(sizeof(struct sgl_handle *) *
+ phba->params.ios_per_ctrl,
+ GFP_KERNEL);
+ if (!phba->io_sgl_hndl_base) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Mem Alloc Failed. Failing to load\n");
+ return -ENOMEM;
+ }
+ phba->eh_sgl_hndl_base = kzalloc(sizeof(struct sgl_handle *) *
+ (phba->params.icds_per_ctrl -
+ phba->params.ios_per_ctrl),
+ GFP_KERNEL);
+ if (!phba->eh_sgl_hndl_base) {
+ kfree(phba->io_sgl_hndl_base);
+ shost_printk(KERN_ERR, phba->shost,
+ "Mem Alloc Failed. Failing to load\n");
+ return -ENOMEM;
+ }
+ } else {
+ shost_printk(KERN_ERR, phba->shost,
+ "HWI_MEM_SGLH is more than one element."
+ "Failing to load\n");
+ return -ENOMEM;
+ }
+
+ arr_index = 0;
+ idx = 0;
+ while (idx < mem_descr_sglh->num_elements) {
+ psgl_handle = mem_descr_sglh->mem_array[idx].virtual_address;
+
+ for (i = 0; i < (mem_descr_sglh->mem_array[idx].size /
+ sizeof(struct sgl_handle)); i++) {
+ if (arr_index < phba->params.ios_per_ctrl) {
+ phba->io_sgl_hndl_base[arr_index] = psgl_handle;
+ phba->io_sgl_hndl_avbl++;
+ arr_index++;
+ } else {
+ phba->eh_sgl_hndl_base[arr_index -
+ phba->params.ios_per_ctrl] =
+ psgl_handle;
+ arr_index++;
+ phba->eh_sgl_hndl_avbl++;
+ }
+ psgl_handle++;
+ }
+ idx++;
+ }
+ SE_DEBUG(DBG_LVL_8,
+ "phba->io_sgl_hndl_avbl=%d"
+ "phba->eh_sgl_hndl_avbl=%d \n",
+ phba->io_sgl_hndl_avbl,
+ phba->eh_sgl_hndl_avbl);
+ mem_descr_sg = phba->init_mem;
+ mem_descr_sg += HWI_MEM_SGE;
+ SE_DEBUG(DBG_LVL_8, "\n mem_descr_sg->num_elements=%d \n",
+ mem_descr_sg->num_elements);
+ arr_index = 0;
+ idx = 0;
+ while (idx < mem_descr_sg->num_elements) {
+ pfrag = mem_descr_sg->mem_array[idx].virtual_address;
+
+ for (i = 0;
+ i < (mem_descr_sg->mem_array[idx].size) /
+ (sizeof(struct iscsi_sge) * phba->params.num_sge_per_io);
+ i++) {
+ if (arr_index < phba->params.ios_per_ctrl)
+ psgl_handle = phba->io_sgl_hndl_base[arr_index];
+ else
+ psgl_handle = phba->eh_sgl_hndl_base[arr_index -
+ phba->params.ios_per_ctrl];
+ psgl_handle->pfrag = pfrag;
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, pfrag, 0);
+ AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, pfrag, 0);
+ pfrag += phba->params.num_sge_per_io;
+ psgl_handle->sgl_index =
+ phba->fw_config.iscsi_cid_start + arr_index++;
+ }
+ idx++;
+ }
+ phba->io_sgl_free_index = 0;
+ phba->io_sgl_alloc_index = 0;
+ phba->eh_sgl_free_index = 0;
+ phba->eh_sgl_alloc_index = 0;
+ return 0;
+}
+
+static int hba_setup_cid_tbls(struct beiscsi_hba *phba)
+{
+ int i, new_cid;
+
+ phba->cid_array = kmalloc(sizeof(void *) * phba->params.cxns_per_ctrl,
+ GFP_KERNEL);
+ if (!phba->cid_array) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Failed to allocate memory in "
+ "hba_setup_cid_tbls\n");
+ return -ENOMEM;
+ }
+ phba->ep_array = kmalloc(sizeof(struct iscsi_endpoint *) *
+ phba->params.cxns_per_ctrl * 2, GFP_KERNEL);
+ if (!phba->ep_array) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Failed to allocate memory in "
+ "hba_setup_cid_tbls \n");
+ kfree(phba->cid_array);
+ return -ENOMEM;
+ }
+ new_cid = phba->fw_config.iscsi_icd_start;
+ for (i = 0; i < phba->params.cxns_per_ctrl; i++) {
+ phba->cid_array[i] = new_cid;
+ new_cid += 2;
+ }
+ phba->avlbl_cids = phba->params.cxns_per_ctrl;
+ return 0;
+}
+
+static unsigned char hwi_enable_intr(struct beiscsi_hba *phba)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_queue_info *eq;
+ u8 __iomem *addr;
+ u32 reg;
+ u32 enabled;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+
+ eq = &phwi_context->be_eq.q;
+ addr = (u8 __iomem *) ((u8 __iomem *) ctrl->pcicfg +
+ PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET);
+ reg = ioread32(addr);
+ SE_DEBUG(DBG_LVL_8, "reg =x%08x \n", reg);
+
+ enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+ if (!enabled) {
+ reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+ SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p \n", reg, addr);
+ iowrite32(reg, addr);
+ SE_DEBUG(DBG_LVL_8, "eq->id=%d \n", eq->id);
+
+ hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "In hwi_enable_intr, Not Enabled \n");
+ return true;
+}
+
+static void hwi_disable_intr(struct beiscsi_hba *phba)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+
+ u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET;
+ u32 reg = ioread32(addr);
+
+ u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+ if (enabled) {
+ reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+ iowrite32(reg, addr);
+ } else
+ shost_printk(KERN_WARNING, phba->shost,
+ "In hwi_disable_intr, Already Disabled \n");
+}
+
+static int beiscsi_init_port(struct beiscsi_hba *phba)
+{
+ int ret;
+
+ ret = beiscsi_init_controller(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "beiscsi_dev_probe - Failed in"
+ "beiscsi_init_controller \n");
+ return ret;
+ }
+ ret = beiscsi_init_sgl_handle(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost,
+ "beiscsi_dev_probe - Failed in"
+ "beiscsi_init_sgl_handle \n");
+ goto do_cleanup_ctrlr;
+ }
+
+ if (hba_setup_cid_tbls(phba)) {
+ shost_printk(KERN_ERR, phba->shost,
+ "Failed in hba_setup_cid_tbls\n");
+ kfree(phba->io_sgl_hndl_base);
+ kfree(phba->eh_sgl_hndl_base);
+ goto do_cleanup_ctrlr;
+ }
+
+ return ret;
+
+do_cleanup_ctrlr:
+ hwi_cleanup(phba);
+ return ret;
+}
+
+static void hwi_purge_eq(struct beiscsi_hba *phba)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct be_queue_info *eq;
+ struct be_eq_entry *eqe = NULL;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ eq = &phwi_context->be_eq.q;
+ eqe = queue_tail_node(eq);
+
+ while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32]
+ & EQE_VALID_MASK) {
+ AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0);
+ queue_tail_inc(eq);
+ eqe = queue_tail_node(eq);
+ }
+}
+
+static void beiscsi_clean_port(struct beiscsi_hba *phba)
+{
+ unsigned char mgmt_status;
+
+ mgmt_status = mgmt_epfw_cleanup(phba, CMD_CONNECTION_CHUTE_0);
+ if (mgmt_status)
+ shost_printk(KERN_WARNING, phba->shost,
+ "mgmt_epfw_cleanup FAILED \n");
+ hwi_cleanup(phba);
+ hwi_purge_eq(phba);
+ kfree(phba->io_sgl_hndl_base);
+ kfree(phba->eh_sgl_hndl_base);
+ kfree(phba->cid_array);
+ kfree(phba->ep_array);
+}
+
+void
+beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_offload_params *params)
+{
+ struct wrb_handle *pwrb_handle;
+ struct iscsi_target_context_update_wrb *pwrb = NULL;
+ struct be_mem_descriptor *mem_descr;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ u32 doorbell = 0;
+
+ /*
+ * We can always use 0 here because it is reserved by libiscsi for
+ * login/startup related tasks.
+ */
+ pwrb_handle = alloc_wrb_handle(phba, beiscsi_conn->beiscsi_conn_cid, 0);
+ pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb;
+ memset(pwrb, 0, sizeof(*pwrb));
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ max_burst_length, pwrb, params->dw[offsetof
+ (struct amap_beiscsi_offload_params,
+ max_burst_length) / 32]);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ max_send_data_segment_length, pwrb,
+ params->dw[offsetof(struct amap_beiscsi_offload_params,
+ max_send_data_segment_length) / 32]);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ first_burst_length,
+ pwrb,
+ params->dw[offsetof(struct amap_beiscsi_offload_params,
+ first_burst_length) / 32]);
+
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, erl, pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ erl) / 32] & OFFLD_PARAMS_ERL));
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, dde, pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ dde) / 32] & OFFLD_PARAMS_DDE) >> 2);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, hde, pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ hde) / 32] & OFFLD_PARAMS_HDE) >> 3);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ir2t, pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, imd, pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ imd) / 32] & OFFLD_PARAMS_IMD) >> 5);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, stat_sn,
+ pwrb,
+ (params->dw[offsetof(struct amap_beiscsi_offload_params,
+ exp_statsn) / 32] + 1));
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, type, pwrb,
+ 0x7);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, wrb_idx,
+ pwrb, pwrb_handle->wrb_index);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb,
+ pwrb, pwrb_handle->nxt_wrb_index);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ session_state, pwrb, 0);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack,
+ pwrb, 1);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, notpredblq,
+ pwrb, 0);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, mode, pwrb,
+ 0);
+
+ mem_descr = phba->init_mem;
+ mem_descr += ISCSI_MEM_GLOBAL_HEADER;
+
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ pad_buffer_addr_hi, pwrb,
+ mem_descr->mem_array[0].bus_address.u.a32.address_hi);
+ AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb,
+ pad_buffer_addr_lo, pwrb,
+ mem_descr->mem_array[0].bus_address.u.a32.address_lo);
+
+ be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_target_context_update_wrb));
+
+ doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
+ doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) <<
+ DB_DEF_PDU_WRB_INDEX_SHIFT;
+ doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
+
+ iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET);
+}
+
+static void beiscsi_parse_pdu(struct iscsi_conn *conn, itt_t itt,
+ int *index, int *age)
+{
+ *index = be32_to_cpu(itt) >> 16;
+ if (age)
+ *age = conn->session->age;
+}
+
+/**
+ * beiscsi_alloc_pdu - allocates pdu and related resources
+ * @task: libiscsi task
+ * @opcode: opcode of pdu for task
+ *
+ * This is called with the session lock held. It will allocate
+ * the wrb and sgl if needed for the command. And it will prep
+ * the pdu's itt. beiscsi_parse_pdu will later translate
+ * the pdu itt to the libiscsi task itt.
+ */
+static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode)
+{
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct hwi_wrb_context *pwrb_context;
+ struct hwi_controller *phwi_ctrlr;
+ itt_t itt;
+ struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess;
+ dma_addr_t paddr;
+
+ io_task->cmd_bhs = pci_pool_alloc(beiscsi_sess->bhs_pool,
+ GFP_KERNEL, &paddr);
+
+ if (!io_task->cmd_bhs)
+ return -ENOMEM;
+
+ io_task->bhs_pa.u.a64.address = paddr;
+ io_task->pwrb_handle = alloc_wrb_handle(phba,
+ beiscsi_conn->beiscsi_conn_cid,
+ task->itt);
+ io_task->pwrb_handle->pio_handle = task;
+ io_task->conn = beiscsi_conn;
+
+ task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr;
+ task->hdr_max = sizeof(struct be_cmd_bhs);
+
+ if (task->sc) {
+ spin_lock(&phba->io_sgl_lock);
+ io_task->psgl_handle = alloc_io_sgl_handle(phba);
+ spin_unlock(&phba->io_sgl_lock);
+ if (!io_task->psgl_handle)
+ goto free_hndls;
+
+ } else {
+ io_task->scsi_cmnd = NULL;
+ if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) {
+ if (!beiscsi_conn->login_in_progress) {
+ spin_lock(&phba->mgmt_sgl_lock);
+ io_task->psgl_handle = (struct sgl_handle *)
+ alloc_mgmt_sgl_handle(phba);
+ spin_unlock(&phba->mgmt_sgl_lock);
+ if (!io_task->psgl_handle)
+ goto free_hndls;
+
+ beiscsi_conn->login_in_progress = 1;
+ beiscsi_conn->plogin_sgl_handle =
+ io_task->psgl_handle;
+ } else {
+ io_task->psgl_handle =
+ beiscsi_conn->plogin_sgl_handle;
+ }
+ } else {
+ spin_lock(&phba->mgmt_sgl_lock);
+ io_task->psgl_handle = alloc_mgmt_sgl_handle(phba);
+ spin_unlock(&phba->mgmt_sgl_lock);
+ if (!io_task->psgl_handle)
+ goto free_hndls;
+ }
+ }
+ itt = (itt_t) cpu_to_be32(((unsigned int)task->itt << 16) |
+ (unsigned int)(io_task->psgl_handle->sgl_index));
+ io_task->cmd_bhs->iscsi_hdr.itt = itt;
+ return 0;
+
+free_hndls:
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid];
+ free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
+ io_task->pwrb_handle = NULL;
+ pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
+ io_task->bhs_pa.u.a64.address);
+ SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed \n");
+ return -ENOMEM;
+}
+
+static void beiscsi_cleanup_task(struct iscsi_task *task)
+{
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess;
+ struct hwi_wrb_context *pwrb_context;
+ struct hwi_controller *phwi_ctrlr;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid];
+ if (io_task->pwrb_handle) {
+ free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle);
+ io_task->pwrb_handle = NULL;
+ }
+
+ if (io_task->cmd_bhs) {
+ pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs,
+ io_task->bhs_pa.u.a64.address);
+ }
+
+ if (task->sc) {
+ if (io_task->psgl_handle) {
+ spin_lock(&phba->io_sgl_lock);
+ free_io_sgl_handle(phba, io_task->psgl_handle);
+ spin_unlock(&phba->io_sgl_lock);
+ io_task->psgl_handle = NULL;
+ }
+ } else {
+ if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN)
+ return;
+ if (io_task->psgl_handle) {
+ spin_lock(&phba->mgmt_sgl_lock);
+ free_mgmt_sgl_handle(phba, io_task->psgl_handle);
+ spin_unlock(&phba->mgmt_sgl_lock);
+ io_task->psgl_handle = NULL;
+ }
+ }
+}
+
+static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg,
+ unsigned int num_sg, unsigned int xferlen,
+ unsigned int writedir)
+{
+
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct iscsi_wrb *pwrb = NULL;
+ unsigned int doorbell = 0;
+
+ pwrb = io_task->pwrb_handle->pwrb;
+ io_task->cmd_bhs->iscsi_hdr.exp_statsn = 0;
+ io_task->bhs_len = sizeof(struct be_cmd_bhs);
+
+ if (writedir) {
+ SE_DEBUG(DBG_LVL_4, " WRITE Command \t");
+ memset(&io_task->cmd_bhs->iscsi_data_pdu, 0, 48);
+ AMAP_SET_BITS(struct amap_pdu_data_out, itt,
+ &io_task->cmd_bhs->iscsi_data_pdu,
+ (unsigned int)io_task->cmd_bhs->iscsi_hdr.itt);
+ AMAP_SET_BITS(struct amap_pdu_data_out, opcode,
+ &io_task->cmd_bhs->iscsi_data_pdu,
+ ISCSI_OPCODE_SCSI_DATA_OUT);
+ AMAP_SET_BITS(struct amap_pdu_data_out, final_bit,
+ &io_task->cmd_bhs->iscsi_data_pdu, 1);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_WR_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1);
+ } else {
+ SE_DEBUG(DBG_LVL_4, "READ Command \t");
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_RD_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0);
+ }
+ memcpy(&io_task->cmd_bhs->iscsi_data_pdu.
+ dw[offsetof(struct amap_pdu_data_out, lun) / 32],
+ io_task->cmd_bhs->iscsi_hdr.lun, sizeof(struct scsi_lun));
+
+ AMAP_SET_BITS(struct amap_iscsi_wrb, lun, pwrb,
+ cpu_to_be16((unsigned short)io_task->cmd_bhs->iscsi_hdr.
+ lun[0]));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, xferlen);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb,
+ io_task->pwrb_handle->wrb_index);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb,
+ be32_to_cpu(task->cmdsn));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb,
+ io_task->psgl_handle->sgl_index);
+
+ hwi_write_sgl(pwrb, sg, num_sg, io_task);
+
+ AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb,
+ io_task->pwrb_handle->nxt_wrb_index);
+ be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
+
+ doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
+ doorbell |= (io_task->pwrb_handle->wrb_index &
+ DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT;
+ doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
+
+ iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET);
+ return 0;
+}
+
+static int beiscsi_mtask(struct iscsi_task *task)
+{
+ struct beiscsi_io_task *aborted_io_task, *io_task = task->dd_data;
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct beiscsi_hba *phba = beiscsi_conn->phba;
+ struct iscsi_wrb *pwrb = NULL;
+ unsigned int doorbell = 0;
+ struct iscsi_task *aborted_task;
+
+ pwrb = io_task->pwrb_handle->pwrb;
+ AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb,
+ be32_to_cpu(task->cmdsn));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb,
+ io_task->pwrb_handle->wrb_index);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb,
+ io_task->psgl_handle->sgl_index);
+
+ switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
+ case ISCSI_OP_LOGIN:
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, TGT_DM_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1);
+ hwi_write_buffer(pwrb, task);
+ break;
+ case ISCSI_OP_NOOP_OUT:
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_RD_CMD);
+ hwi_write_buffer(pwrb, task);
+ break;
+ case ISCSI_OP_TEXT:
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_WR_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1);
+ hwi_write_buffer(pwrb, task);
+ break;
+ case ISCSI_OP_SCSI_TMFUNC:
+ aborted_task = iscsi_itt_to_task(conn,
+ ((struct iscsi_tm *)task->hdr)->rtt);
+ if (!aborted_task)
+ return 0;
+ aborted_io_task = aborted_task->dd_data;
+ if (!aborted_io_task->scsi_cmnd)
+ return 0;
+
+ mgmt_invalidate_icds(phba,
+ aborted_io_task->psgl_handle->sgl_index,
+ beiscsi_conn->beiscsi_conn_cid);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, INI_TMF_CMD);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
+ hwi_write_buffer(pwrb, task);
+ break;
+ case ISCSI_OP_LOGOUT:
+ AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0);
+ AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb,
+ HWH_TYPE_LOGOUT);
+ hwi_write_buffer(pwrb, task);
+ break;
+
+ default:
+ SE_DEBUG(DBG_LVL_1, "opcode =%d Not supported \n",
+ task->hdr->opcode & ISCSI_OPCODE_MASK);
+ return -EINVAL;
+ }
+
+ AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb,
+ be32_to_cpu(task->data_count));
+ AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb,
+ io_task->pwrb_handle->nxt_wrb_index);
+ be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb));
+
+ doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK;
+ doorbell |= (io_task->pwrb_handle->wrb_index &
+ DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT;
+ doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT;
+ iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET);
+ return 0;
+}
+
+static int beiscsi_task_xmit(struct iscsi_task *task)
+{
+ struct iscsi_conn *conn = task->conn;
+ struct beiscsi_io_task *io_task = task->dd_data;
+ struct scsi_cmnd *sc = task->sc;
+ struct beiscsi_conn *beiscsi_conn = conn->dd_data;
+ struct scatterlist *sg;
+ int num_sg;
+ unsigned int writedir = 0, xferlen = 0;
+
+ SE_DEBUG(DBG_LVL_4, "\n cid=%d In beiscsi_task_xmit task=%p conn=%p \t"
+ "beiscsi_conn=%p \n", beiscsi_conn->beiscsi_conn_cid,
+ task, conn, beiscsi_conn);
+ if (!sc)
+ return beiscsi_mtask(task);
+
+ io_task->scsi_cmnd = sc;
+ num_sg = scsi_dma_map(sc);
+ if (num_sg < 0) {
+ SE_DEBUG(DBG_LVL_1, " scsi_dma_map Failed\n")
+ return num_sg;
+ }
+ SE_DEBUG(DBG_LVL_4, "xferlen=0x%08x scmd=%p num_sg=%d sernum=%lu\n",
+ (scsi_bufflen(sc)), sc, num_sg, sc->serial_number);
+ xferlen = scsi_bufflen(sc);
+ sg = scsi_sglist(sc);
+ if (sc->sc_data_direction == DMA_TO_DEVICE) {
+ writedir = 1;
+ SE_DEBUG(DBG_LVL_4, "task->imm_count=0x%08x \n",
+ task->imm_count);
+ } else
+ writedir = 0;
+ return beiscsi_iotask(task, sg, num_sg, xferlen, writedir);
+}
+
+static void beiscsi_remove(struct pci_dev *pcidev)
+{
+ struct beiscsi_hba *phba = NULL;
+
+ phba = (struct beiscsi_hba *)pci_get_drvdata(pcidev);
+ if (!phba) {
+ dev_err(&pcidev->dev, "beiscsi_remove called with no phba \n");
+ return;
+ }
+
+ hwi_disable_intr(phba);
+ if (phba->pcidev->irq)
+ free_irq(phba->pcidev->irq, phba);
+ destroy_workqueue(phba->wq);
+ if (blk_iopoll_enabled)
+ blk_iopoll_disable(&phba->iopoll);
+
+ beiscsi_clean_port(phba);
+ beiscsi_free_mem(phba);
+ beiscsi_unmap_pci_function(phba);
+ pci_free_consistent(phba->pcidev,
+ phba->ctrl.mbox_mem_alloced.size,
+ phba->ctrl.mbox_mem_alloced.va,
+ phba->ctrl.mbox_mem_alloced.dma);
+ iscsi_host_remove(phba->shost);
+ pci_dev_put(phba->pcidev);
+ iscsi_host_free(phba->shost);
+}
+
+static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev,
+ const struct pci_device_id *id)
+{
+ struct beiscsi_hba *phba = NULL;
+ int ret;
+
+ ret = beiscsi_enable_pci(pcidev);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed to enable pci device \n");
+ return ret;
+ }
+
+ phba = beiscsi_hba_alloc(pcidev);
+ if (!phba) {
+ dev_err(&pcidev->dev, "beiscsi_dev_probe-"
+ " Failed in beiscsi_hba_alloc \n");
+ goto disable_pci;
+ }
+
+ pci_set_drvdata(pcidev, phba);
+ ret = be_ctrl_init(phba, pcidev);
+ if (ret) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed in be_ctrl_init\n");
+ goto hba_free;
+ }
+
+ spin_lock_init(&phba->io_sgl_lock);
+ spin_lock_init(&phba->mgmt_sgl_lock);
+ spin_lock_init(&phba->isr_lock);
+ beiscsi_get_params(phba);
+ ret = beiscsi_init_port(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed in beiscsi_init_port\n");
+ goto free_port;
+ }
+
+ snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_q_irq%u",
+ phba->shost->host_no);
+ phba->wq = create_singlethread_workqueue(phba->wq_name);
+ if (!phba->wq) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed to allocate work queue\n");
+ goto free_twq;
+ }
+
+ INIT_WORK(&phba->work_cqs, beiscsi_process_all_cqs);
+
+ if (blk_iopoll_enabled) {
+ blk_iopoll_init(&phba->iopoll, be_iopoll_budget, be_iopoll);
+ blk_iopoll_enable(&phba->iopoll);
+ }
+
+ ret = beiscsi_init_irqs(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed to beiscsi_init_irqs\n");
+ goto free_blkenbld;
+ }
+ ret = hwi_enable_intr(phba);
+ if (ret < 0) {
+ shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-"
+ "Failed to hwi_enable_intr\n");
+ goto free_ctrlr;
+ }
+
+ SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED \n\n\n");
+ return 0;
+
+free_ctrlr:
+ if (phba->pcidev->irq)
+ free_irq(phba->pcidev->irq, phba);
+free_blkenbld:
+ destroy_workqueue(phba->wq);
+ if (blk_iopoll_enabled)
+ blk_iopoll_disable(&phba->iopoll);
+free_twq:
+ beiscsi_clean_port(phba);
+ beiscsi_free_mem(phba);
+free_port:
+ pci_free_consistent(phba->pcidev,
+ phba->ctrl.mbox_mem_alloced.size,
+ phba->ctrl.mbox_mem_alloced.va,
+ phba->ctrl.mbox_mem_alloced.dma);
+ beiscsi_unmap_pci_function(phba);
+hba_free:
+ iscsi_host_remove(phba->shost);
+ pci_dev_put(phba->pcidev);
+ iscsi_host_free(phba->shost);
+disable_pci:
+ pci_disable_device(pcidev);
+ return ret;
+}
+
+struct iscsi_transport beiscsi_iscsi_transport = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ .caps = CAP_RECOVERY_L0 | CAP_HDRDGST |
+ CAP_MULTI_R2T | CAP_DATADGST | CAP_DATA_PATH_OFFLOAD,
+ .param_mask = ISCSI_MAX_RECV_DLENGTH |
+ ISCSI_MAX_XMIT_DLENGTH |
+ ISCSI_HDRDGST_EN |
+ ISCSI_DATADGST_EN |
+ ISCSI_INITIAL_R2T_EN |
+ ISCSI_MAX_R2T |
+ ISCSI_IMM_DATA_EN |
+ ISCSI_FIRST_BURST |
+ ISCSI_MAX_BURST |
+ ISCSI_PDU_INORDER_EN |
+ ISCSI_DATASEQ_INORDER_EN |
+ ISCSI_ERL |
+ ISCSI_CONN_PORT |
+ ISCSI_CONN_ADDRESS |
+ ISCSI_EXP_STATSN |
+ ISCSI_PERSISTENT_PORT |
+ ISCSI_PERSISTENT_ADDRESS |
+ ISCSI_TARGET_NAME | ISCSI_TPGT |
+ ISCSI_USERNAME | ISCSI_PASSWORD |
+ ISCSI_USERNAME_IN | ISCSI_PASSWORD_IN |
+ ISCSI_FAST_ABORT | ISCSI_ABORT_TMO |
+ ISCSI_LU_RESET_TMO |
+ ISCSI_PING_TMO | ISCSI_RECV_TMO |
+ ISCSI_IFACE_NAME | ISCSI_INITIATOR_NAME,
+ .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS |
+ ISCSI_HOST_INITIATOR_NAME,
+ .create_session = beiscsi_session_create,
+ .destroy_session = beiscsi_session_destroy,
+ .create_conn = beiscsi_conn_create,
+ .bind_conn = beiscsi_conn_bind,
+ .destroy_conn = iscsi_conn_teardown,
+ .set_param = beiscsi_set_param,
+ .get_conn_param = beiscsi_conn_get_param,
+ .get_session_param = iscsi_session_get_param,
+ .get_host_param = beiscsi_get_host_param,
+ .start_conn = beiscsi_conn_start,
+ .stop_conn = beiscsi_conn_stop,
+ .send_pdu = iscsi_conn_send_pdu,
+ .xmit_task = beiscsi_task_xmit,
+ .cleanup_task = beiscsi_cleanup_task,
+ .alloc_pdu = beiscsi_alloc_pdu,
+ .parse_pdu_itt = beiscsi_parse_pdu,
+ .get_stats = beiscsi_conn_get_stats,
+ .ep_connect = beiscsi_ep_connect,
+ .ep_poll = beiscsi_ep_poll,
+ .ep_disconnect = beiscsi_ep_disconnect,
+ .session_recovery_timedout = iscsi_session_recovery_timedout,
+};
+
+static struct pci_driver beiscsi_pci_driver = {
+ .name = DRV_NAME,
+ .probe = beiscsi_dev_probe,
+ .remove = beiscsi_remove,
+ .id_table = beiscsi_pci_id_table
+};
+
+static int __init beiscsi_module_init(void)
+{
+ int ret;
+
+ beiscsi_scsi_transport =
+ iscsi_register_transport(&beiscsi_iscsi_transport);
+ if (!beiscsi_scsi_transport) {
+ SE_DEBUG(DBG_LVL_1,
+ "beiscsi_module_init - Unable to register beiscsi"
+ "transport.\n");
+ ret = -ENOMEM;
+ }
+ SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p \n",
+ &beiscsi_iscsi_transport);
+
+ ret = pci_register_driver(&beiscsi_pci_driver);
+ if (ret) {
+ SE_DEBUG(DBG_LVL_1,
+ "beiscsi_module_init - Unable to register"
+ "beiscsi pci driver.\n");
+ goto unregister_iscsi_transport;
+ }
+ return 0;
+
+unregister_iscsi_transport:
+ iscsi_unregister_transport(&beiscsi_iscsi_transport);
+ return ret;
+}
+
+static void __exit beiscsi_module_exit(void)
+{
+ pci_unregister_driver(&beiscsi_pci_driver);
+ iscsi_unregister_transport(&beiscsi_iscsi_transport);
+}
+
+module_init(beiscsi_module_init);
+module_exit(beiscsi_module_exit);
diff --git a/drivers/scsi/be2iscsi/be_main.h b/drivers/scsi/be2iscsi/be_main.h
new file mode 100644
index 000000000000..53c9b70ac7ac
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_main.h
@@ -0,0 +1,837 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * 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. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+
+#ifndef _BEISCSI_MAIN_
+#define _BEISCSI_MAIN_
+
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/in.h>
+#include <linux/blk-iopoll.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/iscsi_proto.h>
+#include <scsi/libiscsi.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+#include "be.h"
+
+
+
+#define DRV_NAME "be2iscsi"
+#define BUILD_STR "2.0.527.0"
+
+#define BE_NAME "ServerEngines BladeEngine2" \
+ "Linux iSCSI Driver version" BUILD_STR
+#define DRV_DESC BE_NAME " " "Driver"
+
+#define BE_VENDOR_ID 0x19A2
+#define BE_DEVICE_ID1 0x212
+#define OC_DEVICE_ID1 0x702
+#define OC_DEVICE_ID2 0x703
+
+#define BE2_MAX_SESSIONS 64
+#define BE2_CMDS_PER_CXN 128
+#define BE2_LOGOUTS BE2_MAX_SESSIONS
+#define BE2_TMFS 16
+#define BE2_NOPOUT_REQ 16
+#define BE2_ASYNCPDUS BE2_MAX_SESSIONS
+#define BE2_MAX_ICDS 2048
+#define BE2_SGE 32
+#define BE2_DEFPDU_HDR_SZ 64
+#define BE2_DEFPDU_DATA_SZ 8192
+#define BE2_IO_DEPTH \
+ (BE2_MAX_ICDS / 2 - (BE2_LOGOUTS + BE2_TMFS + BE2_NOPOUT_REQ))
+
+#define BEISCSI_SGLIST_ELEMENTS BE2_SGE
+
+#define BEISCSI_MAX_CMNDS 1024 /* Max IO's per Ctrlr sht->can_queue */
+#define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */
+#define BEISCSI_MAX_SECTORS 2048 /* scsi_host->max_sectors */
+
+#define BEISCSI_MAX_CMD_LEN 16 /* scsi_host->max_cmd_len */
+#define BEISCSI_NUM_MAX_LUN 256 /* scsi_host->max_lun */
+#define BEISCSI_NUM_DEVICES_SUPPORTED 0x01
+#define BEISCSI_MAX_FRAGS_INIT 192
+#define BE_NUM_MSIX_ENTRIES 1
+#define MPU_EP_SEMAPHORE 0xac
+
+#define BE_SENSE_INFO_SIZE 258
+#define BE_ISCSI_PDU_HEADER_SIZE 64
+#define BE_MIN_MEM_SIZE 16384
+
+#define IIOC_SCSI_DATA 0x05 /* Write Operation */
+
+#define DBG_LVL 0x00000001
+#define DBG_LVL_1 0x00000001
+#define DBG_LVL_2 0x00000002
+#define DBG_LVL_3 0x00000004
+#define DBG_LVL_4 0x00000008
+#define DBG_LVL_5 0x00000010
+#define DBG_LVL_6 0x00000020
+#define DBG_LVL_7 0x00000040
+#define DBG_LVL_8 0x00000080
+
+#define SE_DEBUG(debug_mask, fmt, args...) \
+do { \
+ if (debug_mask & DBG_LVL) { \
+ printk(KERN_ERR "(%s():%d):", __func__, __LINE__);\
+ printk(fmt, ##args); \
+ } \
+} while (0);
+
+/**
+ * hardware needs the async PDU buffers to be posted in multiples of 8
+ * So have atleast 8 of them by default
+ */
+
+#define HWI_GET_ASYNC_PDU_CTX(phwi) (phwi->phwi_ctxt->pasync_ctx)
+
+/********* Memory BAR register ************/
+#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc
+/**
+ * Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt
+ * Disable" may still globally block interrupts in addition to individual
+ * interrupt masks; a mechanism for the device driver to block all interrupts
+ * atomically without having to arbitrate for the PCI Interrupt Disable bit
+ * with the OS.
+ */
+#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */
+
+/********* ISR0 Register offset **********/
+#define CEV_ISR0_OFFSET 0xC18
+#define CEV_ISR_SIZE 4
+
+/**
+ * Macros for reading/writing a protection domain or CSR registers
+ * in BladeEngine.
+ */
+
+#define DB_TXULP0_OFFSET 0x40
+#define DB_RXULP0_OFFSET 0xA0
+/********* Event Q door bell *************/
+#define DB_EQ_OFFSET DB_CQ_OFFSET
+#define DB_EQ_RING_ID_MASK 0x1FF /* bits 0 - 8 */
+/* Clear the interrupt for this eq */
+#define DB_EQ_CLR_SHIFT (9) /* bit 9 */
+/* Must be 1 */
+#define DB_EQ_EVNT_SHIFT (10) /* bit 10 */
+/* Number of event entries processed */
+#define DB_EQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
+/* Rearm bit */
+#define DB_EQ_REARM_SHIFT (29) /* bit 29 */
+
+/********* Compl Q door bell *************/
+#define DB_CQ_OFFSET 0x120
+#define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */
+/* Number of event entries processed */
+#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */
+/* Rearm bit */
+#define DB_CQ_REARM_SHIFT (29) /* bit 29 */
+
+#define GET_HWI_CONTROLLER_WS(pc) (pc->phwi_ctrlr)
+#define HWI_GET_DEF_BUFQ_ID(pc) (((struct hwi_controller *)\
+ (GET_HWI_CONTROLLER_WS(pc)))->default_pdu_data.id)
+#define HWI_GET_DEF_HDRQ_ID(pc) (((struct hwi_controller *)\
+ (GET_HWI_CONTROLLER_WS(pc)))->default_pdu_hdr.id)
+
+#define PAGES_REQUIRED(x) \
+ ((x < PAGE_SIZE) ? 1 : ((x + PAGE_SIZE - 1) / PAGE_SIZE))
+
+enum be_mem_enum {
+ HWI_MEM_ADDN_CONTEXT,
+ HWI_MEM_CQ,
+ HWI_MEM_EQ,
+ HWI_MEM_WRB,
+ HWI_MEM_WRBH,
+ HWI_MEM_SGLH, /* 5 */
+ HWI_MEM_SGE,
+ HWI_MEM_ASYNC_HEADER_BUF,
+ HWI_MEM_ASYNC_DATA_BUF,
+ HWI_MEM_ASYNC_HEADER_RING,
+ HWI_MEM_ASYNC_DATA_RING, /* 10 */
+ HWI_MEM_ASYNC_HEADER_HANDLE,
+ HWI_MEM_ASYNC_DATA_HANDLE,
+ HWI_MEM_ASYNC_PDU_CONTEXT,
+ ISCSI_MEM_GLOBAL_HEADER,
+ SE_MEM_MAX /* 15 */
+};
+
+struct be_bus_address32 {
+ unsigned int address_lo;
+ unsigned int address_hi;
+};
+
+struct be_bus_address64 {
+ unsigned long long address;
+};
+
+struct be_bus_address {
+ union {
+ struct be_bus_address32 a32;
+ struct be_bus_address64 a64;
+ } u;
+};
+
+struct mem_array {
+ struct be_bus_address bus_address; /* Bus address of location */
+ void *virtual_address; /* virtual address to the location */
+ unsigned int size; /* Size required by memory block */
+};
+
+struct be_mem_descriptor {
+ unsigned int index; /* Index of this memory parameter */
+ unsigned int category; /* type indicates cached/non-cached */
+ unsigned int num_elements; /* number of elements in this
+ * descriptor
+ */
+ unsigned int alignment_mask; /* Alignment mask for this block */
+ unsigned int size_in_bytes; /* Size required by memory block */
+ struct mem_array *mem_array;
+};
+
+struct sgl_handle {
+ unsigned int sgl_index;
+ struct iscsi_sge *pfrag;
+};
+
+struct hba_parameters {
+ unsigned int ios_per_ctrl;
+ unsigned int cxns_per_ctrl;
+ unsigned int asyncpdus_per_ctrl;
+ unsigned int icds_per_ctrl;
+ unsigned int num_sge_per_io;
+ unsigned int defpdu_hdr_sz;
+ unsigned int defpdu_data_sz;
+ unsigned int num_cq_entries;
+ unsigned int num_eq_entries;
+ unsigned int wrbs_per_cxn;
+ unsigned int crashmode;
+ unsigned int hba_num;
+
+ unsigned int mgmt_ws_sz;
+ unsigned int hwi_ws_sz;
+
+ unsigned int eto;
+ unsigned int ldto;
+
+ unsigned int dbg_flags;
+ unsigned int num_cxn;
+
+ unsigned int eq_timer;
+ /**
+ * These are calculated from other params. They're here
+ * for debug purposes
+ */
+ unsigned int num_mcc_pages;
+ unsigned int num_mcc_cq_pages;
+ unsigned int num_cq_pages;
+ unsigned int num_eq_pages;
+
+ unsigned int num_async_pdu_buf_pages;
+ unsigned int num_async_pdu_buf_sgl_pages;
+ unsigned int num_async_pdu_buf_cq_pages;
+
+ unsigned int num_async_pdu_hdr_pages;
+ unsigned int num_async_pdu_hdr_sgl_pages;
+ unsigned int num_async_pdu_hdr_cq_pages;
+
+ unsigned int num_sge;
+};
+
+struct beiscsi_hba {
+ struct hba_parameters params;
+ struct hwi_controller *phwi_ctrlr;
+ unsigned int mem_req[SE_MEM_MAX];
+ /* PCI BAR mapped addresses */
+ u8 __iomem *csr_va; /* CSR */
+ u8 __iomem *db_va; /* Door Bell */
+ u8 __iomem *pci_va; /* PCI Config */
+ struct be_bus_address csr_pa; /* CSR */
+ struct be_bus_address db_pa; /* CSR */
+ struct be_bus_address pci_pa; /* CSR */
+ /* PCI representation of our HBA */
+ struct pci_dev *pcidev;
+ unsigned int state;
+ unsigned short asic_revision;
+ struct blk_iopoll iopoll;
+ struct be_mem_descriptor *init_mem;
+
+ unsigned short io_sgl_alloc_index;
+ unsigned short io_sgl_free_index;
+ unsigned short io_sgl_hndl_avbl;
+ struct sgl_handle **io_sgl_hndl_base;
+
+ unsigned short eh_sgl_alloc_index;
+ unsigned short eh_sgl_free_index;
+ unsigned short eh_sgl_hndl_avbl;
+ struct sgl_handle **eh_sgl_hndl_base;
+ spinlock_t io_sgl_lock;
+ spinlock_t mgmt_sgl_lock;
+ spinlock_t isr_lock;
+ unsigned int age;
+ unsigned short avlbl_cids;
+ unsigned short cid_alloc;
+ unsigned short cid_free;
+ struct beiscsi_conn *conn_table[BE2_MAX_SESSIONS * 2];
+ struct list_head hba_queue;
+ unsigned short *cid_array;
+ struct iscsi_endpoint **ep_array;
+ struct Scsi_Host *shost;
+ struct {
+ /**
+ * group together since they are used most frequently
+ * for cid to cri conversion
+ */
+ unsigned int iscsi_cid_start;
+ unsigned int phys_port;
+
+ unsigned int isr_offset;
+ unsigned int iscsi_icd_start;
+ unsigned int iscsi_cid_count;
+ unsigned int iscsi_icd_count;
+ unsigned int pci_function;
+
+ unsigned short cid_alloc;
+ unsigned short cid_free;
+ unsigned short avlbl_cids;
+ spinlock_t cid_lock;
+ } fw_config;
+
+ u8 mac_address[ETH_ALEN];
+ unsigned short todo_cq;
+ unsigned short todo_mcc_cq;
+ char wq_name[20];
+ struct workqueue_struct *wq; /* The actuak work queue */
+ struct work_struct work_cqs; /* The work being queued */
+ struct be_ctrl_info ctrl;
+};
+
+struct beiscsi_session {
+ struct pci_pool *bhs_pool;
+};
+
+/**
+ * struct beiscsi_conn - iscsi connection structure
+ */
+struct beiscsi_conn {
+ struct iscsi_conn *conn;
+ struct beiscsi_hba *phba;
+ u32 exp_statsn;
+ u32 beiscsi_conn_cid;
+ struct beiscsi_endpoint *ep;
+ unsigned short login_in_progress;
+ struct sgl_handle *plogin_sgl_handle;
+ struct beiscsi_session *beiscsi_sess;
+};
+
+/* This structure is used by the chip */
+struct pdu_data_out {
+ u32 dw[12];
+};
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_pdu_data_out {
+ u8 opcode[6]; /* opcode */
+ u8 rsvd0[2]; /* should be 0 */
+ u8 rsvd1[7];
+ u8 final_bit; /* F bit */
+ u8 rsvd2[16];
+ u8 ahs_length[8]; /* no AHS */
+ u8 data_len_hi[8];
+ u8 data_len_lo[16]; /* DataSegmentLength */
+ u8 lun[64];
+ u8 itt[32]; /* ITT; initiator task tag */
+ u8 ttt[32]; /* TTT; valid for R2T or 0xffffffff */
+ u8 rsvd3[32];
+ u8 exp_stat_sn[32];
+ u8 rsvd4[32];
+ u8 data_sn[32];
+ u8 buffer_offset[32];
+ u8 rsvd5[32];
+};
+
+struct be_cmd_bhs {
+ struct iscsi_cmd iscsi_hdr;
+ unsigned char pad1[16];
+ struct pdu_data_out iscsi_data_pdu;
+ unsigned char pad2[BE_SENSE_INFO_SIZE -
+ sizeof(struct pdu_data_out)];
+};
+
+struct beiscsi_io_task {
+ struct wrb_handle *pwrb_handle;
+ struct sgl_handle *psgl_handle;
+ struct beiscsi_conn *conn;
+ struct scsi_cmnd *scsi_cmnd;
+ unsigned int cmd_sn;
+ unsigned int flags;
+ unsigned short cid;
+ unsigned short header_len;
+
+ struct be_cmd_bhs *cmd_bhs;
+ struct be_bus_address bhs_pa;
+ unsigned short bhs_len;
+};
+
+struct be_nonio_bhs {
+ struct iscsi_hdr iscsi_hdr;
+ unsigned char pad1[16];
+ struct pdu_data_out iscsi_data_pdu;
+ unsigned char pad2[BE_SENSE_INFO_SIZE -
+ sizeof(struct pdu_data_out)];
+};
+
+struct be_status_bhs {
+ struct iscsi_cmd iscsi_hdr;
+ unsigned char pad1[16];
+ /**
+ * The plus 2 below is to hold the sense info length that gets
+ * DMA'ed by RxULP
+ */
+ unsigned char sense_info[BE_SENSE_INFO_SIZE];
+};
+
+struct iscsi_sge {
+ u32 dw[4];
+};
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_iscsi_sge {
+ u8 addr_hi[32];
+ u8 addr_lo[32];
+ u8 sge_offset[22]; /* DWORD 2 */
+ u8 rsvd0[9]; /* DWORD 2 */
+ u8 last_sge; /* DWORD 2 */
+ u8 len[17]; /* DWORD 3 */
+ u8 rsvd1[15]; /* DWORD 3 */
+};
+
+struct beiscsi_offload_params {
+ u32 dw[5];
+};
+
+#define OFFLD_PARAMS_ERL 0x00000003
+#define OFFLD_PARAMS_DDE 0x00000004
+#define OFFLD_PARAMS_HDE 0x00000008
+#define OFFLD_PARAMS_IR2T 0x00000010
+#define OFFLD_PARAMS_IMD 0x00000020
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_beiscsi_offload_params {
+ u8 max_burst_length[32];
+ u8 max_send_data_segment_length[32];
+ u8 first_burst_length[32];
+ u8 erl[2];
+ u8 dde[1];
+ u8 hde[1];
+ u8 ir2t[1];
+ u8 imd[1];
+ u8 pad[26];
+ u8 exp_statsn[32];
+};
+
+/* void hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn,
+ struct beiscsi_hba *phba, struct sol_cqe *psol);*/
+
+struct async_pdu_handle {
+ struct list_head link;
+ struct be_bus_address pa;
+ void *pbuffer;
+ unsigned int consumed;
+ unsigned char index;
+ unsigned char is_header;
+ unsigned short cri;
+ unsigned long buffer_len;
+};
+
+struct hwi_async_entry {
+ struct {
+ unsigned char hdr_received;
+ unsigned char hdr_len;
+ unsigned short bytes_received;
+ unsigned int bytes_needed;
+ struct list_head list;
+ } wait_queue;
+
+ struct list_head header_busy_list;
+ struct list_head data_busy_list;
+};
+
+#define BE_MIN_ASYNC_ENTRIES 128
+
+struct hwi_async_pdu_context {
+ struct {
+ struct be_bus_address pa_base;
+ void *va_base;
+ void *ring_base;
+ struct async_pdu_handle *handle_base;
+
+ unsigned int host_write_ptr;
+ unsigned int ep_read_ptr;
+ unsigned int writables;
+
+ unsigned int free_entries;
+ unsigned int busy_entries;
+ unsigned int buffer_size;
+ unsigned int num_entries;
+
+ struct list_head free_list;
+ } async_header;
+
+ struct {
+ struct be_bus_address pa_base;
+ void *va_base;
+ void *ring_base;
+ struct async_pdu_handle *handle_base;
+
+ unsigned int host_write_ptr;
+ unsigned int ep_read_ptr;
+ unsigned int writables;
+
+ unsigned int free_entries;
+ unsigned int busy_entries;
+ unsigned int buffer_size;
+ struct list_head free_list;
+ unsigned int num_entries;
+ } async_data;
+
+ /**
+ * This is a varying size list! Do not add anything
+ * after this entry!!
+ */
+ struct hwi_async_entry async_entry[BE_MIN_ASYNC_ENTRIES];
+};
+
+#define PDUCQE_CODE_MASK 0x0000003F
+#define PDUCQE_DPL_MASK 0xFFFF0000
+#define PDUCQE_INDEX_MASK 0x0000FFFF
+
+struct i_t_dpdu_cqe {
+ u32 dw[4];
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_i_t_dpdu_cqe {
+ u8 db_addr_hi[32];
+ u8 db_addr_lo[32];
+ u8 code[6];
+ u8 cid[10];
+ u8 dpl[16];
+ u8 index[16];
+ u8 num_cons[10];
+ u8 rsvd0[4];
+ u8 final;
+ u8 valid;
+} __packed;
+
+#define CQE_VALID_MASK 0x80000000
+#define CQE_CODE_MASK 0x0000003F
+#define CQE_CID_MASK 0x0000FFC0
+
+#define EQE_VALID_MASK 0x00000001
+#define EQE_MAJORCODE_MASK 0x0000000E
+#define EQE_RESID_MASK 0xFFFF0000
+
+struct be_eq_entry {
+ u32 dw[1];
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_eq_entry {
+ u8 valid; /* DWORD 0 */
+ u8 major_code[3]; /* DWORD 0 */
+ u8 minor_code[12]; /* DWORD 0 */
+ u8 resource_id[16]; /* DWORD 0 */
+
+} __packed;
+
+struct cq_db {
+ u32 dw[1];
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_cq_db {
+ u8 qid[10];
+ u8 event[1];
+ u8 rsvd0[5];
+ u8 num_popped[13];
+ u8 rearm[1];
+ u8 rsvd1[2];
+} __packed;
+
+void beiscsi_process_eq(struct beiscsi_hba *phba);
+
+
+struct iscsi_wrb {
+ u32 dw[16];
+} __packed;
+
+#define WRB_TYPE_MASK 0xF0000000
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_iscsi_wrb {
+ u8 lun[14]; /* DWORD 0 */
+ u8 lt; /* DWORD 0 */
+ u8 invld; /* DWORD 0 */
+ u8 wrb_idx[8]; /* DWORD 0 */
+ u8 dsp; /* DWORD 0 */
+ u8 dmsg; /* DWORD 0 */
+ u8 undr_run; /* DWORD 0 */
+ u8 over_run; /* DWORD 0 */
+ u8 type[4]; /* DWORD 0 */
+ u8 ptr2nextwrb[8]; /* DWORD 1 */
+ u8 r2t_exp_dtl[24]; /* DWORD 1 */
+ u8 sgl_icd_idx[12]; /* DWORD 2 */
+ u8 rsvd0[20]; /* DWORD 2 */
+ u8 exp_data_sn[32]; /* DWORD 3 */
+ u8 iscsi_bhs_addr_hi[32]; /* DWORD 4 */
+ u8 iscsi_bhs_addr_lo[32]; /* DWORD 5 */
+ u8 cmdsn_itt[32]; /* DWORD 6 */
+ u8 dif_ref_tag[32]; /* DWORD 7 */
+ u8 sge0_addr_hi[32]; /* DWORD 8 */
+ u8 sge0_addr_lo[32]; /* DWORD 9 */
+ u8 sge0_offset[22]; /* DWORD 10 */
+ u8 pbs; /* DWORD 10 */
+ u8 dif_mode[2]; /* DWORD 10 */
+ u8 rsvd1[6]; /* DWORD 10 */
+ u8 sge0_last; /* DWORD 10 */
+ u8 sge0_len[17]; /* DWORD 11 */
+ u8 dif_meta_tag[14]; /* DWORD 11 */
+ u8 sge0_in_ddr; /* DWORD 11 */
+ u8 sge1_addr_hi[32]; /* DWORD 12 */
+ u8 sge1_addr_lo[32]; /* DWORD 13 */
+ u8 sge1_r2t_offset[22]; /* DWORD 14 */
+ u8 rsvd2[9]; /* DWORD 14 */
+ u8 sge1_last; /* DWORD 14 */
+ u8 sge1_len[17]; /* DWORD 15 */
+ u8 ref_sgl_icd_idx[12]; /* DWORD 15 */
+ u8 rsvd3[2]; /* DWORD 15 */
+ u8 sge1_in_ddr; /* DWORD 15 */
+
+} __packed;
+
+struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid,
+ int index);
+void
+free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle);
+
+struct pdu_nop_out {
+ u32 dw[12];
+};
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_pdu_nop_out {
+ u8 opcode[6]; /* opcode 0x00 */
+ u8 i_bit; /* I Bit */
+ u8 x_bit; /* reserved; should be 0 */
+ u8 fp_bit_filler1[7];
+ u8 f_bit; /* always 1 */
+ u8 reserved1[16];
+ u8 ahs_length[8]; /* no AHS */
+ u8 data_len_hi[8];
+ u8 data_len_lo[16]; /* DataSegmentLength */
+ u8 lun[64];
+ u8 itt[32]; /* initiator id for ping or 0xffffffff */
+ u8 ttt[32]; /* target id for ping or 0xffffffff */
+ u8 cmd_sn[32];
+ u8 exp_stat_sn[32];
+ u8 reserved5[128];
+};
+
+#define PDUBASE_OPCODE_MASK 0x0000003F
+#define PDUBASE_DATALENHI_MASK 0x0000FF00
+#define PDUBASE_DATALENLO_MASK 0xFFFF0000
+
+struct pdu_base {
+ u32 dw[16];
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_pdu_base {
+ u8 opcode[6];
+ u8 i_bit; /* immediate bit */
+ u8 x_bit; /* reserved, always 0 */
+ u8 reserved1[24]; /* opcode-specific fields */
+ u8 ahs_length[8]; /* length units is 4 byte words */
+ u8 data_len_hi[8];
+ u8 data_len_lo[16]; /* DatasegmentLength */
+ u8 lun[64]; /* lun or opcode-specific fields */
+ u8 itt[32]; /* initiator task tag */
+ u8 reserved4[224];
+};
+
+struct iscsi_target_context_update_wrb {
+ u32 dw[16];
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_iscsi_target_context_update_wrb {
+ u8 lun[14]; /* DWORD 0 */
+ u8 lt; /* DWORD 0 */
+ u8 invld; /* DWORD 0 */
+ u8 wrb_idx[8]; /* DWORD 0 */
+ u8 dsp; /* DWORD 0 */
+ u8 dmsg; /* DWORD 0 */
+ u8 undr_run; /* DWORD 0 */
+ u8 over_run; /* DWORD 0 */
+ u8 type[4]; /* DWORD 0 */
+ u8 ptr2nextwrb[8]; /* DWORD 1 */
+ u8 max_burst_length[19]; /* DWORD 1 */
+ u8 rsvd0[5]; /* DWORD 1 */
+ u8 rsvd1[15]; /* DWORD 2 */
+ u8 max_send_data_segment_length[17]; /* DWORD 2 */
+ u8 first_burst_length[14]; /* DWORD 3 */
+ u8 rsvd2[2]; /* DWORD 3 */
+ u8 tx_wrbindex_drv_msg[8]; /* DWORD 3 */
+ u8 rsvd3[5]; /* DWORD 3 */
+ u8 session_state[3]; /* DWORD 3 */
+ u8 rsvd4[16]; /* DWORD 4 */
+ u8 tx_jumbo; /* DWORD 4 */
+ u8 hde; /* DWORD 4 */
+ u8 dde; /* DWORD 4 */
+ u8 erl[2]; /* DWORD 4 */
+ u8 domain_id[5]; /* DWORD 4 */
+ u8 mode; /* DWORD 4 */
+ u8 imd; /* DWORD 4 */
+ u8 ir2t; /* DWORD 4 */
+ u8 notpredblq[2]; /* DWORD 4 */
+ u8 compltonack; /* DWORD 4 */
+ u8 stat_sn[32]; /* DWORD 5 */
+ u8 pad_buffer_addr_hi[32]; /* DWORD 6 */
+ u8 pad_buffer_addr_lo[32]; /* DWORD 7 */
+ u8 pad_addr_hi[32]; /* DWORD 8 */
+ u8 pad_addr_lo[32]; /* DWORD 9 */
+ u8 rsvd5[32]; /* DWORD 10 */
+ u8 rsvd6[32]; /* DWORD 11 */
+ u8 rsvd7[32]; /* DWORD 12 */
+ u8 rsvd8[32]; /* DWORD 13 */
+ u8 rsvd9[32]; /* DWORD 14 */
+ u8 rsvd10[32]; /* DWORD 15 */
+
+} __packed;
+
+struct be_ring {
+ u32 pages; /* queue size in pages */
+ u32 id; /* queue id assigned by beklib */
+ u32 num; /* number of elements in queue */
+ u32 cidx; /* consumer index */
+ u32 pidx; /* producer index -- not used by most rings */
+ u32 item_size; /* size in bytes of one object */
+
+ void *va; /* The virtual address of the ring. This
+ * should be last to allow 32 & 64 bit debugger
+ * extensions to work.
+ */
+};
+
+struct hwi_wrb_context {
+ struct list_head wrb_handle_list;
+ struct list_head wrb_handle_drvr_list;
+ struct wrb_handle **pwrb_handle_base;
+ struct wrb_handle **pwrb_handle_basestd;
+ struct iscsi_wrb *plast_wrb;
+ unsigned short alloc_index;
+ unsigned short free_index;
+ unsigned short wrb_handles_available;
+ unsigned short cid;
+};
+
+struct hwi_controller {
+ struct list_head io_sgl_list;
+ struct list_head eh_sgl_list;
+ struct sgl_handle *psgl_handle_base;
+ unsigned int wrb_mem_index;
+
+ struct hwi_wrb_context wrb_context[BE2_MAX_SESSIONS * 2];
+ struct mcc_wrb *pmcc_wrb_base;
+ struct be_ring default_pdu_hdr;
+ struct be_ring default_pdu_data;
+ struct hwi_context_memory *phwi_ctxt;
+ unsigned short cq_errors[CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN];
+};
+
+enum hwh_type_enum {
+ HWH_TYPE_IO = 1,
+ HWH_TYPE_LOGOUT = 2,
+ HWH_TYPE_TMF = 3,
+ HWH_TYPE_NOP = 4,
+ HWH_TYPE_IO_RD = 5,
+ HWH_TYPE_LOGIN = 11,
+ HWH_TYPE_INVALID = 0xFFFFFFFF
+};
+
+struct wrb_handle {
+ enum hwh_type_enum type;
+ unsigned short wrb_index;
+ unsigned short nxt_wrb_index;
+
+ struct iscsi_task *pio_handle;
+ struct iscsi_wrb *pwrb;
+};
+
+struct hwi_context_memory {
+ struct be_eq_obj be_eq;
+ struct be_queue_info be_cq;
+ struct be_queue_info be_mcc_cq;
+ struct be_queue_info be_mcc;
+
+ struct be_queue_info be_def_hdrq;
+ struct be_queue_info be_def_dataq;
+
+ struct be_queue_info be_wrbq[BE2_MAX_SESSIONS];
+ struct be_mcc_wrb_context *pbe_mcc_context;
+
+ struct hwi_async_pdu_context *pasync_ctx;
+};
+
+#endif
diff --git a/drivers/scsi/be2iscsi/be_mgmt.c b/drivers/scsi/be2iscsi/be_mgmt.c
new file mode 100644
index 000000000000..12e644fc746e
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_mgmt.c
@@ -0,0 +1,321 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * 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. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+
+#include "be_mgmt.h"
+#include "be_iscsi.h"
+
+unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba)
+{
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_fw_cfg *req = embedded_payload(wrb);
+ int status = 0;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req));
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ struct be_fw_cfg *pfw_cfg;
+ pfw_cfg = req;
+ phba->fw_config.phys_port = pfw_cfg->phys_port;
+ phba->fw_config.iscsi_icd_start =
+ pfw_cfg->ulp[0].icd_base;
+ phba->fw_config.iscsi_icd_count =
+ pfw_cfg->ulp[0].icd_count;
+ phba->fw_config.iscsi_cid_start =
+ pfw_cfg->ulp[0].sq_base;
+ phba->fw_config.iscsi_cid_count =
+ pfw_cfg->ulp[0].sq_count;
+ } else {
+ shost_printk(KERN_WARNING, phba->shost,
+ "Failed in mgmt_get_fw_config \n");
+ }
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+unsigned char mgmt_check_supported_fw(struct be_ctrl_info *ctrl)
+{
+ struct be_dma_mem nonemb_cmd;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_mgmt_controller_attributes *req;
+ struct be_sge *sge = nonembedded_sgl(wrb);
+ int status = 0;
+
+ nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev,
+ sizeof(struct be_mgmt_controller_attributes),
+ &nonemb_cmd.dma);
+ if (nonemb_cmd.va == NULL) {
+ SE_DEBUG(DBG_LVL_1,
+ "Failed to allocate memory for mgmt_check_supported_fw"
+ "\n");
+ return -1;
+ }
+ nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes);
+ req = nonemb_cmd.va;
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+ OPCODE_COMMON_GET_CNTL_ATTRIBUTES, sizeof(*req));
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd.size);
+
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ struct be_mgmt_controller_attributes_resp *resp = nonemb_cmd.va;
+ SE_DEBUG(DBG_LVL_8, "Firmware version of CMD: %s\n",
+ resp->params.hba_attribs.flashrom_version_string);
+ SE_DEBUG(DBG_LVL_8, "Firmware version is : %s\n",
+ resp->params.hba_attribs.firmware_version_string);
+ SE_DEBUG(DBG_LVL_8,
+ "Developer Build, not performing version check...\n");
+
+ } else
+ SE_DEBUG(DBG_LVL_1, " Failed in mgmt_check_supported_fw\n");
+ if (nonemb_cmd.va)
+ pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct iscsi_cleanup_req *req = embedded_payload(wrb);
+ int status = 0;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req));
+
+ req->chute = chute;
+ req->hdr_ring_id = 0;
+ req->data_ring_id = 0;
+
+ status = be_mbox_notify(ctrl);
+ if (status)
+ shost_printk(KERN_WARNING, phba->shost,
+ " mgmt_epfw_cleanup , FAILED\n");
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
+ unsigned int icd, unsigned int cid)
+{
+ struct be_dma_mem nonemb_cmd;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct be_sge *sge = nonembedded_sgl(wrb);
+ struct invalidate_commands_params_in *req;
+ int status = 0;
+
+ nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev,
+ sizeof(struct invalidate_commands_params_in),
+ &nonemb_cmd.dma);
+ if (nonemb_cmd.va == NULL) {
+ SE_DEBUG(DBG_LVL_1,
+ "Failed to allocate memory for"
+ "mgmt_invalidate_icds \n");
+ return -1;
+ }
+ nonemb_cmd.size = sizeof(struct invalidate_commands_params_in);
+ req = nonemb_cmd.va;
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS,
+ sizeof(*req));
+ req->ref_handle = 0;
+ req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE;
+ req->icd_count = 0;
+ req->table[req->icd_count].icd = icd;
+ req->table[req->icd_count].cid = cid;
+ sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma));
+ sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF);
+ sge->len = cpu_to_le32(nonemb_cmd.size);
+
+ status = be_mbox_notify(ctrl);
+ if (status)
+ SE_DEBUG(DBG_LVL_1, "ICDS Invalidation Failed\n");
+ spin_unlock(&ctrl->mbox_lock);
+ if (nonemb_cmd.va)
+ pci_free_consistent(ctrl->pdev, nonemb_cmd.size,
+ nonemb_cmd.va, nonemb_cmd.dma);
+ return status;
+}
+
+unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
+ struct beiscsi_endpoint *beiscsi_ep,
+ unsigned short cid,
+ unsigned short issue_reset,
+ unsigned short savecfg_flag)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct iscsi_invalidate_connection_params_in *req =
+ embedded_payload(wrb);
+ int status = 0;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI,
+ OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION,
+ sizeof(*req));
+ req->session_handle = beiscsi_ep->fw_handle;
+ req->cid = cid;
+ if (issue_reset)
+ req->cleanup_type = CMD_ISCSI_CONNECTION_ISSUE_TCP_RST;
+ else
+ req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE;
+ req->save_cfg = savecfg_flag;
+ status = be_mbox_notify(ctrl);
+ if (status)
+ SE_DEBUG(DBG_LVL_1, "Invalidation Failed\n");
+
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
+ unsigned short cid, unsigned int upload_flag)
+{
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct tcp_upload_params_in *req = embedded_payload(wrb);
+ int status = 0;
+
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD,
+ OPCODE_COMMON_TCP_UPLOAD, sizeof(*req));
+ req->id = (unsigned short)cid;
+ req->upload_type = (unsigned char)upload_flag;
+ status = be_mbox_notify(ctrl);
+ if (status)
+ SE_DEBUG(DBG_LVL_1, "mgmt_upload_connection Failed\n");
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
+
+int mgmt_open_connection(struct beiscsi_hba *phba,
+ struct sockaddr *dst_addr,
+ struct beiscsi_endpoint *beiscsi_ep)
+{
+ struct hwi_controller *phwi_ctrlr;
+ struct hwi_context_memory *phwi_context;
+ struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr;
+ struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr;
+ struct be_ctrl_info *ctrl = &phba->ctrl;
+ struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+ struct tcp_connect_and_offload_in *req = embedded_payload(wrb);
+ unsigned short def_hdr_id;
+ unsigned short def_data_id;
+ struct phys_addr template_address = { 0, 0 };
+ struct phys_addr *ptemplate_address;
+ int status = 0;
+ unsigned short cid = beiscsi_ep->ep_cid;
+
+ phwi_ctrlr = phba->phwi_ctrlr;
+ phwi_context = phwi_ctrlr->phwi_ctxt;
+ def_hdr_id = (unsigned short)HWI_GET_DEF_HDRQ_ID(phba);
+ def_data_id = (unsigned short)HWI_GET_DEF_BUFQ_ID(phba);
+
+ ptemplate_address = &template_address;
+ ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address);
+ spin_lock(&ctrl->mbox_lock);
+ memset(wrb, 0, sizeof(*wrb));
+
+ be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+ be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI,
+ OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD,
+ sizeof(*req));
+ if (dst_addr->sa_family == PF_INET) {
+ __be32 s_addr = daddr_in->sin_addr.s_addr;
+ req->ip_address.ip_type = BE2_IPV4;
+ req->ip_address.ip_address[0] = s_addr & 0x000000ff;
+ req->ip_address.ip_address[1] = (s_addr & 0x0000ff00) >> 8;
+ req->ip_address.ip_address[2] = (s_addr & 0x00ff0000) >> 16;
+ req->ip_address.ip_address[3] = (s_addr & 0xff000000) >> 24;
+ req->tcp_port = ntohs(daddr_in->sin_port);
+ beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr;
+ beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port);
+ beiscsi_ep->ip_type = BE2_IPV4;
+ } else if (dst_addr->sa_family == PF_INET6) {
+ req->ip_address.ip_type = BE2_IPV6;
+ memcpy(&req->ip_address.ip_address,
+ &daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
+ req->tcp_port = ntohs(daddr_in6->sin6_port);
+ beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port);
+ memcpy(&beiscsi_ep->dst6_addr,
+ &daddr_in6->sin6_addr.in6_u.u6_addr8, 16);
+ beiscsi_ep->ip_type = BE2_IPV6;
+ } else{
+ shost_printk(KERN_ERR, phba->shost, "unknown addr family %d\n",
+ dst_addr->sa_family);
+ spin_unlock(&ctrl->mbox_lock);
+ return -EINVAL;
+
+ }
+ req->cid = cid;
+ req->cq_id = phwi_context->be_cq.id;
+ req->defq_id = def_hdr_id;
+ req->hdr_ring_id = def_hdr_id;
+ req->data_ring_id = def_data_id;
+ req->do_offload = 1;
+ req->dataout_template_pa.lo = ptemplate_address->lo;
+ req->dataout_template_pa.hi = ptemplate_address->hi;
+ status = be_mbox_notify(ctrl);
+ if (!status) {
+ struct iscsi_endpoint *ep;
+ struct tcp_connect_and_offload_out *ptcpcnct_out =
+ embedded_payload(wrb);
+
+ ep = phba->ep_array[ptcpcnct_out->cid];
+ beiscsi_ep = ep->dd_data;
+ beiscsi_ep->fw_handle = 0;
+ beiscsi_ep->cid_vld = 1;
+ SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n");
+ } else
+ SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed\n");
+ spin_unlock(&ctrl->mbox_lock);
+ return status;
+}
diff --git a/drivers/scsi/be2iscsi/be_mgmt.h b/drivers/scsi/be2iscsi/be_mgmt.h
new file mode 100644
index 000000000000..00e816ee8070
--- /dev/null
+++ b/drivers/scsi/be2iscsi/be_mgmt.h
@@ -0,0 +1,249 @@
+/**
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * 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. The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Written by: Jayamohan Kallickal (jayamohank@serverengines.com)
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ *
+ */
+
+#ifndef _BEISCSI_MGMT_
+#define _BEISCSI_MGMT_
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include "be_iscsi.h"
+#include "be_main.h"
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_mcc_sge {
+ u8 pa_lo[32]; /* dword 0 */
+ u8 pa_hi[32]; /* dword 1 */
+ u8 length[32]; /* DWORD 2 */
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_mcc_wrb_payload {
+ union {
+ struct amap_mcc_sge sgl[19];
+ u8 embedded[59 * 32]; /* DWORDS 57 to 115 */
+ } u;
+} __packed;
+
+/**
+ * Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field
+ */
+struct amap_mcc_wrb {
+ u8 embedded; /* DWORD 0 */
+ u8 rsvd0[2]; /* DWORD 0 */
+ u8 sge_count[5]; /* DWORD 0 */
+ u8 rsvd1[16]; /* DWORD 0 */
+ u8 special[8]; /* DWORD 0 */
+ u8 payload_length[32];
+ u8 tag[64]; /* DWORD 2 */
+ u8 rsvd2[32]; /* DWORD 4 */
+ struct amap_mcc_wrb_payload payload;
+};
+
+struct mcc_sge {
+ u32 pa_lo; /* dword 0 */
+ u32 pa_hi; /* dword 1 */
+ u32 length; /* DWORD 2 */
+} __packed;
+
+struct mcc_wrb_payload {
+ union {
+ struct mcc_sge sgl[19];
+ u32 embedded[59]; /* DWORDS 57 to 115 */
+ } u;
+} __packed;
+
+#define MCC_WRB_EMBEDDED_MASK 0x00000001
+
+struct mcc_wrb {
+ u32 dw[0]; /* DWORD 0 */
+ u32 payload_length;
+ u32 tag[2]; /* DWORD 2 */
+ u32 rsvd2[1]; /* DWORD 4 */
+ struct mcc_wrb_payload payload;
+};
+
+unsigned char mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute);
+int mgmt_open_connection(struct beiscsi_hba *phba, struct sockaddr *dst_addr,
+ struct beiscsi_endpoint *beiscsi_ep);
+
+unsigned char mgmt_upload_connection(struct beiscsi_hba *phba,
+ unsigned short cid,
+ unsigned int upload_flag);
+unsigned char mgmt_invalidate_icds(struct beiscsi_hba *phba,
+ unsigned int icd, unsigned int cid);
+
+struct iscsi_invalidate_connection_params_in {
+ struct be_cmd_req_hdr hdr;
+ unsigned int session_handle;
+ unsigned short cid;
+ unsigned short unused;
+ unsigned short cleanup_type;
+ unsigned short save_cfg;
+} __packed;
+
+struct iscsi_invalidate_connection_params_out {
+ unsigned int session_handle;
+ unsigned short cid;
+ unsigned short unused;
+} __packed;
+
+union iscsi_invalidate_connection_params {
+ struct iscsi_invalidate_connection_params_in request;
+ struct iscsi_invalidate_connection_params_out response;
+} __packed;
+
+struct invalidate_command_table {
+ unsigned short icd;
+ unsigned short cid;
+} __packed;
+
+struct invalidate_commands_params_in {
+ struct be_cmd_req_hdr hdr;
+ unsigned int ref_handle;
+ unsigned int icd_count;
+ struct invalidate_command_table table[128];
+ unsigned short cleanup_type;
+ unsigned short unused;
+} __packed;
+
+struct invalidate_commands_params_out {
+ unsigned int ref_handle;
+ unsigned int icd_count;
+ unsigned int icd_status[128];
+} __packed;
+
+union invalidate_commands_params {
+ struct invalidate_commands_params_in request;
+ struct invalidate_commands_params_out response;
+} __packed;
+
+struct mgmt_hba_attributes {
+ u8 flashrom_version_string[32];
+ u8 manufacturer_name[32];
+ u32 supported_modes;
+ u8 seeprom_version_lo;
+ u8 seeprom_version_hi;
+ u8 rsvd0[2];
+ u32 fw_cmd_data_struct_version;
+ u32 ep_fw_data_struct_version;
+ u32 future_reserved[12];
+ u32 default_extended_timeout;
+ u8 controller_model_number[32];
+ u8 controller_description[64];
+ u8 controller_serial_number[32];
+ u8 ip_version_string[32];
+ u8 firmware_version_string[32];
+ u8 bios_version_string[32];
+ u8 redboot_version_string[32];
+ u8 driver_version_string[32];
+ u8 fw_on_flash_version_string[32];
+ u32 functionalities_supported;
+ u16 max_cdblength;
+ u8 asic_revision;
+ u8 generational_guid[16];
+ u8 hba_port_count;
+ u16 default_link_down_timeout;
+ u8 iscsi_ver_min_max;
+ u8 multifunction_device;
+ u8 cache_valid;
+ u8 hba_status;
+ u8 max_domains_supported;
+ u8 phy_port;
+ u32 firmware_post_status;
+ u32 hba_mtu[8];
+ u32 future_u32[4];
+} __packed;
+
+struct mgmt_controller_attributes {
+ struct mgmt_hba_attributes hba_attribs;
+ u16 pci_vendor_id;
+ u16 pci_device_id;
+ u16 pci_sub_vendor_id;
+ u16 pci_sub_system_id;
+ u8 pci_bus_number;
+ u8 pci_device_number;
+ u8 pci_function_number;
+ u8 interface_type;
+ u64 unique_identifier;
+ u8 netfilters;
+ u8 rsvd0[3];
+ u8 future_u32[4];
+} __packed;
+
+struct be_mgmt_controller_attributes {
+ struct be_cmd_req_hdr hdr;
+ struct mgmt_controller_attributes params;
+} __packed;
+
+struct be_mgmt_controller_attributes_resp {
+ struct be_cmd_resp_hdr hdr;
+ struct mgmt_controller_attributes params;
+} __packed;
+
+/* configuration management */
+
+#define GET_MGMT_CONTROLLER_WS(phba) (phba->pmgmt_ws)
+
+/* MGMT CMD flags */
+
+#define MGMT_CMDH_FREE (1<<0)
+
+/* --- MGMT_ERROR_CODES --- */
+/* Error Codes returned in the status field of the CMD response header */
+#define MGMT_STATUS_SUCCESS 0 /* The CMD completed without errors */
+#define MGMT_STATUS_FAILED 1 /* Error status in the Status field of */
+ /* the CMD_RESPONSE_HEADER */
+
+#define ISCSI_GET_PDU_TEMPLATE_ADDRESS(pc, pa) {\
+ pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
+ bus_address.u.a32.address_lo; \
+ pa->hi = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\
+ bus_address.u.a32.address_hi; \
+}
+
+struct beiscsi_endpoint {
+ struct beiscsi_hba *phba;
+ struct beiscsi_sess *sess;
+ struct beiscsi_conn *conn;
+ unsigned short ip_type;
+ char dst6_addr[ISCSI_ADDRESS_BUF_LEN];
+ unsigned long dst_addr;
+ unsigned short ep_cid;
+ unsigned int fw_handle;
+ u16 dst_tcpport;
+ u16 cid_vld;
+};
+
+unsigned char mgmt_get_fw_config(struct be_ctrl_info *ctrl,
+ struct beiscsi_hba *phba);
+
+unsigned char mgmt_invalidate_connection(struct beiscsi_hba *phba,
+ struct beiscsi_endpoint *beiscsi_ep,
+ unsigned short cid,
+ unsigned short issue_reset,
+ unsigned short savecfg_flag);
+#endif
diff --git a/drivers/scsi/bfa/Makefile b/drivers/scsi/bfa/Makefile
new file mode 100644
index 000000000000..1d6009490d1c
--- /dev/null
+++ b/drivers/scsi/bfa/Makefile
@@ -0,0 +1,15 @@
+obj-$(CONFIG_SCSI_BFA_FC) := bfa.o
+
+bfa-y := bfad.o bfad_intr.o bfad_os.o bfad_im.o bfad_attr.o bfad_fwimg.o
+
+bfa-y += bfa_core.o bfa_ioc.o bfa_iocfc.o bfa_fcxp.o bfa_lps.o
+bfa-y += bfa_hw_cb.o bfa_hw_ct.o bfa_intr.o bfa_timer.o bfa_rport.o
+bfa-y += bfa_fcport.o bfa_port.o bfa_uf.o bfa_sgpg.o bfa_module.o bfa_ioim.o
+bfa-y += bfa_itnim.o bfa_fcpim.o bfa_tskim.o bfa_log.o bfa_log_module.o
+bfa-y += bfa_csdebug.o bfa_sm.o plog.o
+
+bfa-y += fcbuild.o fabric.o fcpim.o vfapi.o fcptm.o bfa_fcs.o bfa_fcs_port.o
+bfa-y += bfa_fcs_uf.o bfa_fcs_lport.o fab.o fdmi.o ms.o ns.o scn.o loop.o
+bfa-y += lport_api.o n2n.o rport.o rport_api.o rport_ftrs.o vport.o
+
+ccflags-y := -I$(obj) -I$(obj)/include -I$(obj)/include/cna
diff --git a/drivers/scsi/bfa/bfa_callback_priv.h b/drivers/scsi/bfa/bfa_callback_priv.h
new file mode 100644
index 000000000000..1e3265c9f7d4
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_callback_priv.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_CALLBACK_PRIV_H__
+#define __BFA_CALLBACK_PRIV_H__
+
+#include <cs/bfa_q.h>
+
+typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete);
+
+/**
+ * Generic BFA callback element.
+ */
+struct bfa_cb_qe_s {
+ struct list_head qe;
+ bfa_cb_cbfn_t cbfn;
+ bfa_boolean_t once;
+ u32 rsvd;
+ void *cbarg;
+};
+
+#define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do { \
+ (__hcb_qe)->cbfn = (__cbfn); \
+ (__hcb_qe)->cbarg = (__cbarg); \
+ list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q); \
+} while (0)
+
+#define bfa_cb_dequeue(__hcb_qe) list_del(&(__hcb_qe)->qe)
+
+#define bfa_cb_queue_once(__bfa, __hcb_qe, __cbfn, __cbarg) do { \
+ (__hcb_qe)->cbfn = (__cbfn); \
+ (__hcb_qe)->cbarg = (__cbarg); \
+ if (!(__hcb_qe)->once) { \
+ list_add_tail((__hcb_qe), &(__bfa)->comp_q); \
+ (__hcb_qe)->once = BFA_TRUE; \
+ } \
+} while (0)
+
+#define bfa_cb_queue_done(__hcb_qe) do { \
+ (__hcb_qe)->once = BFA_FALSE; \
+} while (0)
+
+#endif /* __BFA_CALLBACK_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_cb_ioim_macros.h b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
new file mode 100644
index 000000000000..961fe439daad
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_cb_ioim_macros.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_cb_ioim_macros.h BFA IOIM driver interface macros.
+ */
+
+#ifndef __BFA_HCB_IOIM_MACROS_H__
+#define __BFA_HCB_IOIM_MACROS_H__
+
+#include <bfa_os_inc.h>
+/*
+ * #include <linux/dma-mapping.h>
+ *
+ * #include <scsi/scsi.h> #include <scsi/scsi_cmnd.h> #include
+ * <scsi/scsi_device.h> #include <scsi/scsi_host.h>
+ */
+#include "bfad_im_compat.h"
+
+/*
+ * task attribute values in FCP-2 FCP_CMND IU
+ */
+#define SIMPLE_Q 0
+#define HEAD_OF_Q 1
+#define ORDERED_Q 2
+#define ACA_Q 4
+#define UNTAGGED 5
+
+static inline lun_t
+bfad_int_to_lun(u32 luno)
+{
+ union {
+ u16 scsi_lun[4];
+ lun_t bfa_lun;
+ } lun;
+
+ lun.bfa_lun = 0;
+ lun.scsi_lun[0] = bfa_os_htons(luno);
+
+ return lun.bfa_lun;
+}
+
+/**
+ * Get LUN for the I/O request
+ */
+#define bfa_cb_ioim_get_lun(__dio) \
+ bfad_int_to_lun(((struct scsi_cmnd *)__dio)->device->lun)
+
+/**
+ * Get CDB for the I/O request
+ */
+static inline u8 *
+bfa_cb_ioim_get_cdb(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+
+ return (u8 *) cmnd->cmnd;
+}
+
+/**
+ * Get I/O direction (read/write) for the I/O request
+ */
+static inline enum fcp_iodir
+bfa_cb_ioim_get_iodir(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ enum dma_data_direction dmadir;
+
+ dmadir = cmnd->sc_data_direction;
+ if (dmadir == DMA_TO_DEVICE)
+ return FCP_IODIR_WRITE;
+ else if (dmadir == DMA_FROM_DEVICE)
+ return FCP_IODIR_READ;
+ else
+ return FCP_IODIR_NONE;
+}
+
+/**
+ * Get IO size in bytes for the I/O request
+ */
+static inline u32
+bfa_cb_ioim_get_size(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+
+ return scsi_bufflen(cmnd);
+}
+
+/**
+ * Get timeout for the I/O request
+ */
+static inline u8
+bfa_cb_ioim_get_timeout(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ /*
+ * TBD: need a timeout for scsi passthru
+ */
+ if (cmnd->device->host == NULL)
+ return 4;
+
+ return 0;
+}
+
+/**
+ * Get SG element for the I/O request given the SG element index
+ */
+static inline union bfi_addr_u
+bfa_cb_ioim_get_sgaddr(struct bfad_ioim_s *dio, int sgeid)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ struct scatterlist *sge;
+ u64 addr;
+
+ sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
+ addr = (u64) sg_dma_address(sge);
+
+ return *((union bfi_addr_u *) &addr);
+}
+
+static inline u32
+bfa_cb_ioim_get_sglen(struct bfad_ioim_s *dio, int sgeid)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ struct scatterlist *sge;
+ u32 len;
+
+ sge = (struct scatterlist *)scsi_sglist(cmnd) + sgeid;
+ len = sg_dma_len(sge);
+
+ return len;
+}
+
+/**
+ * Get Command Reference Number for the I/O request. 0 if none.
+ */
+static inline u8
+bfa_cb_ioim_get_crn(struct bfad_ioim_s *dio)
+{
+ return 0;
+}
+
+/**
+ * Get SAM-3 priority for the I/O request. 0 is default.
+ */
+static inline u8
+bfa_cb_ioim_get_priority(struct bfad_ioim_s *dio)
+{
+ return 0;
+}
+
+/**
+ * Get task attributes for the I/O request. Default is FCP_TASK_ATTR_SIMPLE(0).
+ */
+static inline u8
+bfa_cb_ioim_get_taskattr(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ u8 task_attr = UNTAGGED;
+
+ if (cmnd->device->tagged_supported) {
+ switch (cmnd->tag) {
+ case HEAD_OF_QUEUE_TAG:
+ task_attr = HEAD_OF_Q;
+ break;
+ case ORDERED_QUEUE_TAG:
+ task_attr = ORDERED_Q;
+ break;
+ default:
+ task_attr = SIMPLE_Q;
+ break;
+ }
+ }
+
+ return task_attr;
+}
+
+/**
+ * Get CDB length in bytes for the I/O request. Default is FCP_CMND_CDB_LEN(16).
+ */
+static inline u8
+bfa_cb_ioim_get_cdblen(struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+
+ return cmnd->cmd_len;
+}
+
+
+
+#endif /* __BFA_HCB_IOIM_MACROS_H__ */
diff --git a/drivers/scsi/bfa/bfa_cee.c b/drivers/scsi/bfa/bfa_cee.c
new file mode 100644
index 000000000000..2b917792c6bc
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_cee.c
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <defs/bfa_defs_cee.h>
+#include <cs/bfa_trc.h>
+#include <cs/bfa_log.h>
+#include <cs/bfa_debug.h>
+#include <cee/bfa_cee.h>
+#include <bfi/bfi_cee.h>
+#include <bfi/bfi.h>
+#include <bfa_ioc.h>
+#include <cna/bfa_cna_trcmod.h>
+
+BFA_TRC_FILE(CNA, CEE);
+
+#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
+#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc)
+
+static void bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg_s *lldp_cfg);
+static void bfa_cee_format_dcbcx_stats(struct bfa_cee_dcbx_stats_s
+ *dcbcx_stats);
+static void bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats_s
+ *lldp_stats);
+static void bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats_s *cfg_stats);
+static void bfa_cee_format_cee_cfg(void *buffer);
+static void bfa_cee_format_cee_stats(void *buffer);
+
+static void
+bfa_cee_format_cee_stats(void *buffer)
+{
+ struct bfa_cee_stats_s *cee_stats = buffer;
+ bfa_cee_format_dcbcx_stats(&cee_stats->dcbx_stats);
+ bfa_cee_format_lldp_stats(&cee_stats->lldp_stats);
+ bfa_cee_format_cfg_stats(&cee_stats->cfg_stats);
+}
+
+static void
+bfa_cee_format_cee_cfg(void *buffer)
+{
+ struct bfa_cee_attr_s *cee_cfg = buffer;
+ bfa_cee_format_lldp_cfg(&cee_cfg->lldp_remote);
+}
+
+static void
+bfa_cee_format_dcbcx_stats(struct bfa_cee_dcbx_stats_s *dcbcx_stats)
+{
+ dcbcx_stats->subtlvs_unrecognized =
+ bfa_os_ntohl(dcbcx_stats->subtlvs_unrecognized);
+ dcbcx_stats->negotiation_failed =
+ bfa_os_ntohl(dcbcx_stats->negotiation_failed);
+ dcbcx_stats->remote_cfg_changed =
+ bfa_os_ntohl(dcbcx_stats->remote_cfg_changed);
+ dcbcx_stats->tlvs_received = bfa_os_ntohl(dcbcx_stats->tlvs_received);
+ dcbcx_stats->tlvs_invalid = bfa_os_ntohl(dcbcx_stats->tlvs_invalid);
+ dcbcx_stats->seqno = bfa_os_ntohl(dcbcx_stats->seqno);
+ dcbcx_stats->ackno = bfa_os_ntohl(dcbcx_stats->ackno);
+ dcbcx_stats->recvd_seqno = bfa_os_ntohl(dcbcx_stats->recvd_seqno);
+ dcbcx_stats->recvd_ackno = bfa_os_ntohl(dcbcx_stats->recvd_ackno);
+}
+
+static void
+bfa_cee_format_lldp_stats(struct bfa_cee_lldp_stats_s *lldp_stats)
+{
+ lldp_stats->frames_transmitted =
+ bfa_os_ntohl(lldp_stats->frames_transmitted);
+ lldp_stats->frames_aged_out = bfa_os_ntohl(lldp_stats->frames_aged_out);
+ lldp_stats->frames_discarded =
+ bfa_os_ntohl(lldp_stats->frames_discarded);
+ lldp_stats->frames_in_error = bfa_os_ntohl(lldp_stats->frames_in_error);
+ lldp_stats->frames_rcvd = bfa_os_ntohl(lldp_stats->frames_rcvd);
+ lldp_stats->tlvs_discarded = bfa_os_ntohl(lldp_stats->tlvs_discarded);
+ lldp_stats->tlvs_unrecognized =
+ bfa_os_ntohl(lldp_stats->tlvs_unrecognized);
+}
+
+static void
+bfa_cee_format_cfg_stats(struct bfa_cee_cfg_stats_s *cfg_stats)
+{
+ cfg_stats->cee_status_down = bfa_os_ntohl(cfg_stats->cee_status_down);
+ cfg_stats->cee_status_up = bfa_os_ntohl(cfg_stats->cee_status_up);
+ cfg_stats->cee_hw_cfg_changed =
+ bfa_os_ntohl(cfg_stats->cee_hw_cfg_changed);
+ cfg_stats->recvd_invalid_cfg =
+ bfa_os_ntohl(cfg_stats->recvd_invalid_cfg);
+}
+
+static void
+bfa_cee_format_lldp_cfg(struct bfa_cee_lldp_cfg_s *lldp_cfg)
+{
+ lldp_cfg->time_to_interval = bfa_os_ntohs(lldp_cfg->time_to_interval);
+ lldp_cfg->enabled_system_cap =
+ bfa_os_ntohs(lldp_cfg->enabled_system_cap);
+}
+
+/**
+ * bfa_cee_attr_meminfo()
+ *
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+static u32
+bfa_cee_attr_meminfo(void)
+{
+ return BFA_ROUNDUP(sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ);
+}
+
+/**
+ * bfa_cee_stats_meminfo()
+ *
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+static u32
+bfa_cee_stats_meminfo(void)
+{
+ return BFA_ROUNDUP(sizeof(struct bfa_cee_stats_s), BFA_DMA_ALIGN_SZ);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ *
+ * @param[in] cee - Pointer to the CEE module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_get_attr_isr(struct bfa_cee_s *cee, bfa_status_t status)
+{
+ cee->get_attr_status = status;
+ bfa_trc(cee, 0);
+ if (status == BFA_STATUS_OK) {
+ bfa_trc(cee, 0);
+ /*
+ * The requested data has been copied to the DMA area, *process
+ * it.
+ */
+ memcpy(cee->attr, cee->attr_dma.kva,
+ sizeof(struct bfa_cee_attr_s));
+ bfa_cee_format_cee_cfg(cee->attr);
+ }
+ cee->get_attr_pending = BFA_FALSE;
+ if (cee->cbfn.get_attr_cbfn) {
+ bfa_trc(cee, 0);
+ cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status);
+ }
+ bfa_trc(cee, 0);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ *
+ * @param[in] cee - Pointer to the CEE module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_get_stats_isr(struct bfa_cee_s *cee, bfa_status_t status)
+{
+ cee->get_stats_status = status;
+ bfa_trc(cee, 0);
+ if (status == BFA_STATUS_OK) {
+ bfa_trc(cee, 0);
+ /*
+ * The requested data has been copied to the DMA area, process
+ * it.
+ */
+ memcpy(cee->stats, cee->stats_dma.kva,
+ sizeof(struct bfa_cee_stats_s));
+ bfa_cee_format_cee_stats(cee->stats);
+ }
+ cee->get_stats_pending = BFA_FALSE;
+ bfa_trc(cee, 0);
+ if (cee->cbfn.get_stats_cbfn) {
+ bfa_trc(cee, 0);
+ cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status);
+ }
+ bfa_trc(cee, 0);
+}
+
+/**
+ * bfa_cee_get_attr_isr()
+ *
+ *
+ * @param[in] cee - Pointer to the CEE module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_cee_reset_stats_isr(struct bfa_cee_s *cee, bfa_status_t status)
+{
+ cee->reset_stats_status = status;
+ cee->reset_stats_pending = BFA_FALSE;
+ if (cee->cbfn.reset_stats_cbfn)
+ cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status);
+}
+
+/**
+ * bfa_cee_meminfo()
+ *
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+u32
+bfa_cee_meminfo(void)
+{
+ return bfa_cee_attr_meminfo() + bfa_cee_stats_meminfo();
+}
+
+/**
+ * bfa_cee_mem_claim()
+ *
+ *
+ * @param[in] cee CEE module pointer
+ * dma_kva Kernel Virtual Address of CEE DMA Memory
+ * dma_pa Physical Address of CEE DMA Memory
+ *
+ * @return void
+ */
+void
+bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, u64 dma_pa)
+{
+ cee->attr_dma.kva = dma_kva;
+ cee->attr_dma.pa = dma_pa;
+ cee->stats_dma.kva = dma_kva + bfa_cee_attr_meminfo();
+ cee->stats_dma.pa = dma_pa + bfa_cee_attr_meminfo();
+ cee->attr = (struct bfa_cee_attr_s *)dma_kva;
+ cee->stats =
+ (struct bfa_cee_stats_s *)(dma_kva + bfa_cee_attr_meminfo());
+}
+
+/**
+ * bfa_cee_get_attr()
+ *
+ * Send the request to the f/w to fetch CEE attributes.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+bfa_status_t
+bfa_cee_get_attr(struct bfa_cee_s *cee, struct bfa_cee_attr_s *attr,
+ bfa_cee_get_attr_cbfn_t cbfn, void *cbarg)
+{
+ struct bfi_cee_get_req_s *cmd;
+
+ bfa_assert((cee != NULL) && (cee->ioc != NULL));
+ bfa_trc(cee, 0);
+ if (!bfa_ioc_is_operational(cee->ioc)) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+ if (cee->get_attr_pending == BFA_TRUE) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_DEVBUSY;
+ }
+ cee->get_attr_pending = BFA_TRUE;
+ cmd = (struct bfi_cee_get_req_s *)cee->get_cfg_mb.msg;
+ cee->attr = attr;
+ cee->cbfn.get_attr_cbfn = cbfn;
+ cee->cbfn.get_attr_cbarg = cbarg;
+ bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ,
+ bfa_ioc_portid(cee->ioc));
+ bfa_dma_be_addr_set(cmd->dma_addr, cee->attr_dma.pa);
+ bfa_ioc_mbox_queue(cee->ioc, &cee->get_cfg_mb);
+ bfa_trc(cee, 0);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_cee_get_stats()
+ *
+ * Send the request to the f/w to fetch CEE statistics.
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+bfa_status_t
+bfa_cee_get_stats(struct bfa_cee_s *cee, struct bfa_cee_stats_s *stats,
+ bfa_cee_get_stats_cbfn_t cbfn, void *cbarg)
+{
+ struct bfi_cee_get_req_s *cmd;
+
+ bfa_assert((cee != NULL) && (cee->ioc != NULL));
+
+ if (!bfa_ioc_is_operational(cee->ioc)) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+ if (cee->get_stats_pending == BFA_TRUE) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_DEVBUSY;
+ }
+ cee->get_stats_pending = BFA_TRUE;
+ cmd = (struct bfi_cee_get_req_s *)cee->get_stats_mb.msg;
+ cee->stats = stats;
+ cee->cbfn.get_stats_cbfn = cbfn;
+ cee->cbfn.get_stats_cbarg = cbarg;
+ bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_STATS_REQ,
+ bfa_ioc_portid(cee->ioc));
+ bfa_dma_be_addr_set(cmd->dma_addr, cee->stats_dma.pa);
+ bfa_ioc_mbox_queue(cee->ioc, &cee->get_stats_mb);
+ bfa_trc(cee, 0);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_cee_reset_stats()
+ *
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return Status
+ */
+
+bfa_status_t
+bfa_cee_reset_stats(struct bfa_cee_s *cee, bfa_cee_reset_stats_cbfn_t cbfn,
+ void *cbarg)
+{
+ struct bfi_cee_reset_stats_s *cmd;
+
+ bfa_assert((cee != NULL) && (cee->ioc != NULL));
+ if (!bfa_ioc_is_operational(cee->ioc)) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+ if (cee->reset_stats_pending == BFA_TRUE) {
+ bfa_trc(cee, 0);
+ return BFA_STATUS_DEVBUSY;
+ }
+ cee->reset_stats_pending = BFA_TRUE;
+ cmd = (struct bfi_cee_reset_stats_s *)cee->reset_stats_mb.msg;
+ cee->cbfn.reset_stats_cbfn = cbfn;
+ cee->cbfn.reset_stats_cbarg = cbarg;
+ bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_RESET_STATS,
+ bfa_ioc_portid(cee->ioc));
+ bfa_ioc_mbox_queue(cee->ioc, &cee->reset_stats_mb);
+ bfa_trc(cee, 0);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_cee_isrs()
+ *
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return void
+ */
+
+void
+bfa_cee_isr(void *cbarg, struct bfi_mbmsg_s *m)
+{
+ union bfi_cee_i2h_msg_u *msg;
+ struct bfi_cee_get_rsp_s *get_rsp;
+ struct bfa_cee_s *cee = (struct bfa_cee_s *)cbarg;
+ msg = (union bfi_cee_i2h_msg_u *)m;
+ get_rsp = (struct bfi_cee_get_rsp_s *)m;
+ bfa_trc(cee, msg->mh.msg_id);
+ switch (msg->mh.msg_id) {
+ case BFI_CEE_I2H_GET_CFG_RSP:
+ bfa_trc(cee, get_rsp->cmd_status);
+ bfa_cee_get_attr_isr(cee, get_rsp->cmd_status);
+ break;
+ case BFI_CEE_I2H_GET_STATS_RSP:
+ bfa_cee_get_stats_isr(cee, get_rsp->cmd_status);
+ break;
+ case BFI_CEE_I2H_RESET_STATS_RSP:
+ bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status);
+ break;
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * bfa_cee_hbfail()
+ *
+ *
+ * @param[in] Pointer to the CEE module data structure.
+ *
+ * @return void
+ */
+
+void
+bfa_cee_hbfail(void *arg)
+{
+ struct bfa_cee_s *cee;
+ cee = (struct bfa_cee_s *)arg;
+
+ if (cee->get_attr_pending == BFA_TRUE) {
+ cee->get_attr_status = BFA_STATUS_FAILED;
+ cee->get_attr_pending = BFA_FALSE;
+ if (cee->cbfn.get_attr_cbfn) {
+ cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg,
+ BFA_STATUS_FAILED);
+ }
+ }
+ if (cee->get_stats_pending == BFA_TRUE) {
+ cee->get_stats_status = BFA_STATUS_FAILED;
+ cee->get_stats_pending = BFA_FALSE;
+ if (cee->cbfn.get_stats_cbfn) {
+ cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg,
+ BFA_STATUS_FAILED);
+ }
+ }
+ if (cee->reset_stats_pending == BFA_TRUE) {
+ cee->reset_stats_status = BFA_STATUS_FAILED;
+ cee->reset_stats_pending = BFA_FALSE;
+ if (cee->cbfn.reset_stats_cbfn) {
+ cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg,
+ BFA_STATUS_FAILED);
+ }
+ }
+}
+
+/**
+ * bfa_cee_attach()
+ *
+ *
+ * @param[in] cee - Pointer to the CEE module data structure
+ * ioc - Pointer to the ioc module data structure
+ * dev - Pointer to the device driver module data structure
+ * The device driver specific mbox ISR functions have
+ * this pointer as one of the parameters.
+ * trcmod -
+ * logmod -
+ *
+ * @return void
+ */
+void
+bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, void *dev,
+ struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod)
+{
+ bfa_assert(cee != NULL);
+ cee->dev = dev;
+ cee->trcmod = trcmod;
+ cee->logmod = logmod;
+ cee->ioc = ioc;
+
+ bfa_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee);
+ bfa_ioc_hbfail_init(&cee->hbfail, bfa_cee_hbfail, cee);
+ bfa_ioc_hbfail_register(cee->ioc, &cee->hbfail);
+ bfa_trc(cee, 0);
+}
+
+/**
+ * bfa_cee_detach()
+ *
+ *
+ * @param[in] cee - Pointer to the CEE module data structure
+ *
+ * @return void
+ */
+void
+bfa_cee_detach(struct bfa_cee_s *cee)
+{
+ /*
+ * For now, just check if there is some ioctl pending and mark that as
+ * failed?
+ */
+ /* bfa_cee_hbfail(cee); */
+}
diff --git a/drivers/scsi/bfa/bfa_core.c b/drivers/scsi/bfa/bfa_core.c
new file mode 100644
index 000000000000..44e2d1155c51
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_core.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <defs/bfa_defs_pci.h>
+#include <cs/bfa_debug.h>
+#include <bfa_iocfc.h>
+
+#define DEF_CFG_NUM_FABRICS 1
+#define DEF_CFG_NUM_LPORTS 256
+#define DEF_CFG_NUM_CQS 4
+#define DEF_CFG_NUM_IOIM_REQS (BFA_IOIM_MAX)
+#define DEF_CFG_NUM_TSKIM_REQS 128
+#define DEF_CFG_NUM_FCXP_REQS 64
+#define DEF_CFG_NUM_UF_BUFS 64
+#define DEF_CFG_NUM_RPORTS 1024
+#define DEF_CFG_NUM_ITNIMS (DEF_CFG_NUM_RPORTS)
+#define DEF_CFG_NUM_TINS 256
+
+#define DEF_CFG_NUM_SGPGS 2048
+#define DEF_CFG_NUM_REQQ_ELEMS 256
+#define DEF_CFG_NUM_RSPQ_ELEMS 64
+#define DEF_CFG_NUM_SBOOT_TGTS 16
+#define DEF_CFG_NUM_SBOOT_LUNS 16
+
+/**
+ * Use this function query the memory requirement of the BFA library.
+ * This function needs to be called before bfa_attach() to get the
+ * memory required of the BFA layer for a given driver configuration.
+ *
+ * This call will fail, if the cap is out of range compared to pre-defined
+ * values within the BFA library
+ *
+ * @param[in] cfg - pointer to bfa_ioc_cfg_t. Driver layer should indicate
+ * its configuration in this structure.
+ * The default values for struct bfa_iocfc_cfg_s can be
+ * fetched using bfa_cfg_get_default() API.
+ *
+ * If cap's boundary check fails, the library will use
+ * the default bfa_cap_t values (and log a warning msg).
+ *
+ * @param[out] meminfo - pointer to bfa_meminfo_t. This content
+ * indicates the memory type (see bfa_mem_type_t) and
+ * amount of memory required.
+ *
+ * Driver should allocate the memory, populate the
+ * starting address for each block and provide the same
+ * structure as input parameter to bfa_attach() call.
+ *
+ * @return void
+ *
+ * Special Considerations: @note
+ */
+void
+bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo)
+{
+ int i;
+ u32 km_len = 0, dm_len = 0;
+
+ bfa_assert((cfg != NULL) && (meminfo != NULL));
+
+ bfa_os_memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s));
+ meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_type =
+ BFA_MEM_TYPE_KVA;
+ meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_type =
+ BFA_MEM_TYPE_DMA;
+
+ bfa_iocfc_meminfo(cfg, &km_len, &dm_len);
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->meminfo(cfg, &km_len, &dm_len);
+
+
+ meminfo->meminfo[BFA_MEM_TYPE_KVA - 1].mem_len = km_len;
+ meminfo->meminfo[BFA_MEM_TYPE_DMA - 1].mem_len = dm_len;
+}
+
+/**
+ * Use this function to do attach the driver instance with the BFA
+ * library. This function will not trigger any HW initialization
+ * process (which will be done in bfa_init() call)
+ *
+ * This call will fail, if the cap is out of range compared to
+ * pre-defined values within the BFA library
+ *
+ * @param[out] bfa Pointer to bfa_t.
+ * @param[in] bfad Opaque handle back to the driver's IOC structure
+ * @param[in] cfg Pointer to bfa_ioc_cfg_t. Should be same structure
+ * that was used in bfa_cfg_get_meminfo().
+ * @param[in] meminfo Pointer to bfa_meminfo_t. The driver should
+ * use the bfa_cfg_get_meminfo() call to
+ * find the memory blocks required, allocate the
+ * required memory and provide the starting addresses.
+ * @param[in] pcidev pointer to struct bfa_pcidev_s
+ *
+ * @return
+ * void
+ *
+ * Special Considerations:
+ *
+ * @note
+ *
+ */
+void
+bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ int i;
+ struct bfa_mem_elem_s *melem;
+
+ bfa->fcs = BFA_FALSE;
+
+ bfa_assert((cfg != NULL) && (meminfo != NULL));
+
+ /**
+ * initialize all memory pointers for iterative allocation
+ */
+ for (i = 0; i < BFA_MEM_TYPE_MAX; i++) {
+ melem = meminfo->meminfo + i;
+ melem->kva_curp = melem->kva;
+ melem->dma_curp = melem->dma;
+ }
+
+ bfa_iocfc_attach(bfa, bfad, cfg, meminfo, pcidev);
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->attach(bfa, bfad, cfg, meminfo, pcidev);
+
+}
+
+/**
+ * Use this function to delete a BFA IOC. IOC should be stopped (by
+ * calling bfa_stop()) before this function call.
+ *
+ * @param[in] bfa - pointer to bfa_t.
+ *
+ * @return
+ * void
+ *
+ * Special Considerations:
+ *
+ * @note
+ */
+void
+bfa_detach(struct bfa_s *bfa)
+{
+ int i;
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->detach(bfa);
+
+ bfa_iocfc_detach(bfa);
+}
+
+
+void
+bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod)
+{
+ bfa->trcmod = trcmod;
+}
+
+
+void
+bfa_init_log(struct bfa_s *bfa, struct bfa_log_mod_s *logmod)
+{
+ bfa->logm = logmod;
+}
+
+
+void
+bfa_init_aen(struct bfa_s *bfa, struct bfa_aen_s *aen)
+{
+ bfa->aen = aen;
+}
+
+void
+bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog)
+{
+ bfa->plog = plog;
+}
+
+/**
+ * Initialize IOC.
+ *
+ * This function will return immediately, when the IOC initialization is
+ * completed, the bfa_cb_init() will be called.
+ *
+ * @param[in] bfa instance
+ *
+ * @return void
+ *
+ * Special Considerations:
+ *
+ * @note
+ * When this function returns, the driver should register the interrupt service
+ * routine(s) and enable the device interrupts. If this is not done,
+ * bfa_cb_init() will never get called
+ */
+void
+bfa_init(struct bfa_s *bfa)
+{
+ bfa_iocfc_init(bfa);
+}
+
+/**
+ * Use this function initiate the IOC configuration setup. This function
+ * will return immediately.
+ *
+ * @param[in] bfa instance
+ *
+ * @return None
+ */
+void
+bfa_start(struct bfa_s *bfa)
+{
+ bfa_iocfc_start(bfa);
+}
+
+/**
+ * Use this function quiese the IOC. This function will return immediately,
+ * when the IOC is actually stopped, the bfa_cb_stop() will be called.
+ *
+ * @param[in] bfa - pointer to bfa_t.
+ *
+ * @return None
+ *
+ * Special Considerations:
+ * bfa_cb_stop() could be called before or after bfa_stop() returns.
+ *
+ * @note
+ * In case of any failure, we could handle it automatically by doing a
+ * reset and then succeed the bfa_stop() call.
+ */
+void
+bfa_stop(struct bfa_s *bfa)
+{
+ bfa_iocfc_stop(bfa);
+}
+
+void
+bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q)
+{
+ INIT_LIST_HEAD(comp_q);
+ list_splice_tail_init(&bfa->comp_q, comp_q);
+}
+
+void
+bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q)
+{
+ struct list_head *qe;
+ struct list_head *qen;
+ struct bfa_cb_qe_s *hcb_qe;
+
+ list_for_each_safe(qe, qen, comp_q) {
+ hcb_qe = (struct bfa_cb_qe_s *) qe;
+ hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE);
+ }
+}
+
+void
+bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q)
+{
+ struct list_head *qe;
+ struct bfa_cb_qe_s *hcb_qe;
+
+ while (!list_empty(comp_q)) {
+ bfa_q_deq(comp_q, &qe);
+ hcb_qe = (struct bfa_cb_qe_s *) qe;
+ hcb_qe->cbfn(hcb_qe->cbarg, BFA_FALSE);
+ }
+}
+
+void
+bfa_attach_fcs(struct bfa_s *bfa)
+{
+ bfa->fcs = BFA_TRUE;
+}
+
+/**
+ * Periodic timer heart beat from driver
+ */
+void
+bfa_timer_tick(struct bfa_s *bfa)
+{
+ bfa_timer_beat(&bfa->timer_mod);
+}
+
+#ifndef BFA_BIOS_BUILD
+/**
+ * Return the list of PCI vendor/device id lists supported by this
+ * BFA instance.
+ */
+void
+bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids)
+{
+ static struct bfa_pciid_s __pciids[] = {
+ {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G2P},
+ {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G1P},
+ {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT},
+ };
+
+ *npciids = sizeof(__pciids) / sizeof(__pciids[0]);
+ *pciids = __pciids;
+}
+
+/**
+ * Use this function query the default struct bfa_iocfc_cfg_s value (compiled
+ * into BFA layer). The OS driver can then turn back and overwrite entries that
+ * have been configured by the user.
+ *
+ * @param[in] cfg - pointer to bfa_ioc_cfg_t
+ *
+ * @return
+ * void
+ *
+ * Special Considerations:
+ * note
+ */
+void
+bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg)
+{
+ cfg->fwcfg.num_fabrics = DEF_CFG_NUM_FABRICS;
+ cfg->fwcfg.num_lports = DEF_CFG_NUM_LPORTS;
+ cfg->fwcfg.num_rports = DEF_CFG_NUM_RPORTS;
+ cfg->fwcfg.num_ioim_reqs = DEF_CFG_NUM_IOIM_REQS;
+ cfg->fwcfg.num_tskim_reqs = DEF_CFG_NUM_TSKIM_REQS;
+ cfg->fwcfg.num_fcxp_reqs = DEF_CFG_NUM_FCXP_REQS;
+ cfg->fwcfg.num_uf_bufs = DEF_CFG_NUM_UF_BUFS;
+ cfg->fwcfg.num_cqs = DEF_CFG_NUM_CQS;
+
+ cfg->drvcfg.num_reqq_elems = DEF_CFG_NUM_REQQ_ELEMS;
+ cfg->drvcfg.num_rspq_elems = DEF_CFG_NUM_RSPQ_ELEMS;
+ cfg->drvcfg.num_sgpgs = DEF_CFG_NUM_SGPGS;
+ cfg->drvcfg.num_sboot_tgts = DEF_CFG_NUM_SBOOT_TGTS;
+ cfg->drvcfg.num_sboot_luns = DEF_CFG_NUM_SBOOT_LUNS;
+ cfg->drvcfg.path_tov = BFA_FCPIM_PATHTOV_DEF;
+ cfg->drvcfg.ioc_recover = BFA_FALSE;
+ cfg->drvcfg.delay_comp = BFA_FALSE;
+
+}
+
+void
+bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg)
+{
+ bfa_cfg_get_default(cfg);
+ cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN;
+ cfg->fwcfg.num_tskim_reqs = BFA_TSKIM_MIN;
+ cfg->fwcfg.num_fcxp_reqs = BFA_FCXP_MIN;
+ cfg->fwcfg.num_uf_bufs = BFA_UF_MIN;
+ cfg->fwcfg.num_rports = BFA_RPORT_MIN;
+
+ cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN;
+ cfg->drvcfg.num_reqq_elems = BFA_REQQ_NELEMS_MIN;
+ cfg->drvcfg.num_rspq_elems = BFA_RSPQ_NELEMS_MIN;
+ cfg->drvcfg.min_cfg = BFA_TRUE;
+}
+
+void
+bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr)
+{
+ bfa_ioc_get_attr(&bfa->ioc, ioc_attr);
+}
+
+/**
+ * Retrieve firmware trace information on IOC failure.
+ */
+bfa_status_t
+bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen)
+{
+ return bfa_ioc_debug_fwsave(&bfa->ioc, trcdata, trclen);
+}
+
+/**
+ * Fetch firmware trace data.
+ *
+ * @param[in] bfa BFA instance
+ * @param[out] trcdata Firmware trace buffer
+ * @param[in,out] trclen Firmware trace buffer len
+ *
+ * @retval BFA_STATUS_OK Firmware trace is fetched.
+ * @retval BFA_STATUS_INPROGRESS Firmware trace fetch is in progress.
+ */
+bfa_status_t
+bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen)
+{
+ return bfa_ioc_debug_fwtrc(&bfa->ioc, trcdata, trclen);
+}
+#endif
diff --git a/drivers/scsi/bfa/bfa_csdebug.c b/drivers/scsi/bfa/bfa_csdebug.c
new file mode 100644
index 000000000000..caeb1143a4e6
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_csdebug.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <cs/bfa_debug.h>
+#include <bfa_os_inc.h>
+#include <cs/bfa_q.h>
+#include <log/bfa_log_hal.h>
+
+/**
+ * cs_debug_api
+ */
+
+
+void
+bfa_panic(int line, char *file, char *panicstr)
+{
+ bfa_log(NULL, BFA_LOG_HAL_ASSERT, file, line, panicstr);
+ bfa_os_panic();
+}
+
+void
+bfa_sm_panic(struct bfa_log_mod_s *logm, int line, char *file, int event)
+{
+ bfa_log(logm, BFA_LOG_HAL_SM_ASSERT, file, line, event);
+ bfa_os_panic();
+}
+
+int
+bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe)
+{
+ struct list_head *tqe;
+
+ tqe = bfa_q_next(q);
+ while (tqe != q) {
+ if (tqe == qe)
+ return 1;
+ tqe = bfa_q_next(tqe);
+ if (tqe == NULL)
+ break;
+ }
+ return 0;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcpim.c b/drivers/scsi/bfa/bfa_fcpim.c
new file mode 100644
index 000000000000..790c945aeae6
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcpim.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <log/bfa_log_hal.h>
+
+BFA_TRC_FILE(HAL, FCPIM);
+BFA_MODULE(fcpim);
+
+/**
+ * hal_fcpim_mod BFA FCP Initiator Mode module
+ */
+
+/**
+ * Compute and return memory needed by FCP(im) module.
+ */
+static void
+bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len)
+{
+ bfa_itnim_meminfo(cfg, km_len, dm_len);
+
+ /**
+ * IO memory
+ */
+ if (cfg->fwcfg.num_ioim_reqs < BFA_IOIM_MIN)
+ cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN;
+ else if (cfg->fwcfg.num_ioim_reqs > BFA_IOIM_MAX)
+ cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MAX;
+
+ *km_len += cfg->fwcfg.num_ioim_reqs *
+ (sizeof(struct bfa_ioim_s) + sizeof(struct bfa_ioim_sp_s));
+
+ *dm_len += cfg->fwcfg.num_ioim_reqs * BFI_IOIM_SNSLEN;
+
+ /**
+ * task management command memory
+ */
+ if (cfg->fwcfg.num_tskim_reqs < BFA_TSKIM_MIN)
+ cfg->fwcfg.num_tskim_reqs = BFA_TSKIM_MIN;
+ *km_len += cfg->fwcfg.num_tskim_reqs * sizeof(struct bfa_tskim_s);
+}
+
+
+static void
+bfa_fcpim_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ bfa_trc(bfa, cfg->drvcfg.path_tov);
+ bfa_trc(bfa, cfg->fwcfg.num_rports);
+ bfa_trc(bfa, cfg->fwcfg.num_ioim_reqs);
+ bfa_trc(bfa, cfg->fwcfg.num_tskim_reqs);
+
+ fcpim->bfa = bfa;
+ fcpim->num_itnims = cfg->fwcfg.num_rports;
+ fcpim->num_ioim_reqs = cfg->fwcfg.num_ioim_reqs;
+ fcpim->num_tskim_reqs = cfg->fwcfg.num_tskim_reqs;
+ fcpim->path_tov = cfg->drvcfg.path_tov;
+ fcpim->delay_comp = cfg->drvcfg.delay_comp;
+
+ bfa_itnim_attach(fcpim, meminfo);
+ bfa_tskim_attach(fcpim, meminfo);
+ bfa_ioim_attach(fcpim, meminfo);
+}
+
+static void
+bfa_fcpim_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcpim_detach(struct bfa_s *bfa)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ bfa_ioim_detach(fcpim);
+ bfa_tskim_detach(fcpim);
+}
+
+static void
+bfa_fcpim_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcpim_stop(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcpim_iocdisable(struct bfa_s *bfa)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfa_itnim_s *itnim;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &fcpim->itnim_q) {
+ itnim = (struct bfa_itnim_s *) qe;
+ bfa_itnim_iocdisable(itnim);
+ }
+}
+
+void
+bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ fcpim->path_tov = path_tov * 1000;
+ if (fcpim->path_tov > BFA_FCPIM_PATHTOV_MAX)
+ fcpim->path_tov = BFA_FCPIM_PATHTOV_MAX;
+}
+
+u16
+bfa_fcpim_path_tov_get(struct bfa_s *bfa)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ return fcpim->path_tov / 1000;
+}
+
+bfa_status_t
+bfa_fcpim_get_modstats(struct bfa_s *bfa, struct bfa_fcpim_stats_s *modstats)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ *modstats = fcpim->stats;
+
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_fcpim_clr_modstats(struct bfa_s *bfa)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ memset(&fcpim->stats, 0, sizeof(struct bfa_fcpim_stats_s));
+
+ return BFA_STATUS_OK;
+}
+
+void
+bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ bfa_assert(q_depth <= BFA_IOCFC_QDEPTH_MAX);
+
+ fcpim->q_depth = q_depth;
+}
+
+u16
+bfa_fcpim_qdepth_get(struct bfa_s *bfa)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+
+ return fcpim->q_depth;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcpim_priv.h b/drivers/scsi/bfa/bfa_fcpim_priv.h
new file mode 100644
index 000000000000..5cf418460f75
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcpim_priv.h
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_FCPIM_PRIV_H__
+#define __BFA_FCPIM_PRIV_H__
+
+#include <bfa_fcpim.h>
+#include <defs/bfa_defs_fcpim.h>
+#include <cs/bfa_wc.h>
+#include "bfa_sgpg_priv.h"
+
+#define BFA_ITNIM_MIN 32
+#define BFA_ITNIM_MAX 1024
+
+#define BFA_IOIM_MIN 8
+#define BFA_IOIM_MAX 2000
+
+#define BFA_TSKIM_MIN 4
+#define BFA_TSKIM_MAX 512
+#define BFA_FCPIM_PATHTOV_DEF (30 * 1000) /* in millisecs */
+#define BFA_FCPIM_PATHTOV_MAX (90 * 1000) /* in millisecs */
+
+#define bfa_fcpim_stats(__fcpim, __stats) \
+ ((__fcpim)->stats.__stats++)
+
+struct bfa_fcpim_mod_s {
+ struct bfa_s *bfa;
+ struct bfa_itnim_s *itnim_arr;
+ struct bfa_ioim_s *ioim_arr;
+ struct bfa_ioim_sp_s *ioim_sp_arr;
+ struct bfa_tskim_s *tskim_arr;
+ struct bfa_dma_s snsbase;
+ int num_itnims;
+ int num_ioim_reqs;
+ int num_tskim_reqs;
+ u32 path_tov;
+ u16 q_depth;
+ u16 rsvd;
+ struct list_head itnim_q; /* queue of active itnim */
+ struct list_head ioim_free_q; /* free IO resources */
+ struct list_head ioim_resfree_q; /* IOs waiting for f/w */
+ struct list_head ioim_comp_q; /* IO global comp Q */
+ struct list_head tskim_free_q;
+ u32 ios_active; /* current active IOs */
+ u32 delay_comp;
+ struct bfa_fcpim_stats_s stats;
+};
+
+struct bfa_ioim_s;
+struct bfa_tskim_s;
+
+/**
+ * BFA IO (initiator mode)
+ */
+struct bfa_ioim_s {
+ struct list_head qe; /* queue elememt */
+ bfa_sm_t sm; /* BFA ioim state machine */
+ struct bfa_s *bfa; /* BFA module */
+ struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */
+ struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */
+ struct bfad_ioim_s *dio; /* driver IO handle */
+ u16 iotag; /* FWI IO tag */
+ u16 abort_tag; /* unqiue abort request tag */
+ u16 nsges; /* number of SG elements */
+ u16 nsgpgs; /* number of SG pages */
+ struct bfa_sgpg_s *sgpg; /* first SG page */
+ struct list_head sgpg_q; /* allocated SG pages */
+ struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
+ bfa_cb_cbfn_t io_cbfn; /* IO completion handler */
+ struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */
+};
+
+struct bfa_ioim_sp_s {
+ struct bfi_msg_s comp_rspmsg; /* IO comp f/w response */
+ u8 *snsinfo; /* sense info for this IO */
+ struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */
+ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
+ bfa_boolean_t abort_explicit; /* aborted by OS */
+ struct bfa_tskim_s *tskim; /* Relevant TM cmd */
+};
+
+/**
+ * BFA Task management command (initiator mode)
+ */
+struct bfa_tskim_s {
+ struct list_head qe;
+ bfa_sm_t sm;
+ struct bfa_s *bfa; /* BFA module */
+ struct bfa_fcpim_mod_s *fcpim; /* parent fcpim module */
+ struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */
+ struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */
+ bfa_boolean_t notify; /* notify itnim on TM comp */
+ lun_t lun; /* lun if applicable */
+ enum fcp_tm_cmnd tm_cmnd; /* task management command */
+ u16 tsk_tag; /* FWI IO tag */
+ u8 tsecs; /* timeout in seconds */
+ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
+ struct list_head io_q; /* queue of affected IOs */
+ struct bfa_wc_s wc; /* waiting counter */
+ struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
+ enum bfi_tskim_status tsk_status; /* TM status */
+};
+
+/**
+ * BFA i-t-n (initiator mode)
+ */
+struct bfa_itnim_s {
+ struct list_head qe; /* queue element */
+ bfa_sm_t sm; /* i-t-n im BFA state machine */
+ struct bfa_s *bfa; /* bfa instance */
+ struct bfa_rport_s *rport; /* bfa rport */
+ void *ditn; /* driver i-t-n structure */
+ struct bfi_mhdr_s mhdr; /* pre-built mhdr */
+ u8 msg_no; /* itnim/rport firmware handle */
+ u8 reqq; /* CQ for requests */
+ struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */
+ struct list_head pending_q; /* queue of pending IO requests*/
+ struct list_head io_q; /* queue of active IO requests */
+ struct list_head io_cleanup_q; /* IO being cleaned up */
+ struct list_head tsk_q; /* queue of active TM commands */
+ struct list_head delay_comp_q;/* queue of failed inflight cmds */
+ bfa_boolean_t seq_rec; /* SQER supported */
+ bfa_boolean_t is_online; /* itnim is ONLINE for IO */
+ bfa_boolean_t iotov_active; /* IO TOV timer is active */
+ struct bfa_wc_s wc; /* waiting counter */
+ struct bfa_timer_s timer; /* pending IO TOV */
+ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
+ struct bfa_fcpim_mod_s *fcpim; /* fcpim module */
+ struct bfa_itnim_hal_stats_s stats;
+};
+
+#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])
+#define BFA_TSKIM_FROM_TAG(_fcpim, _tmtag) \
+ (&fcpim->tskim_arr[_tmtag & (fcpim->num_tskim_reqs - 1)])
+
+/*
+ * function prototypes
+ */
+void bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim,
+ struct bfa_meminfo_s *minfo);
+void bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim);
+void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+void bfa_ioim_good_comp_isr(struct bfa_s *bfa,
+ struct bfi_msg_s *msg);
+void bfa_ioim_cleanup(struct bfa_ioim_s *ioim);
+void bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim,
+ struct bfa_tskim_s *tskim);
+void bfa_ioim_iocdisable(struct bfa_ioim_s *ioim);
+void bfa_ioim_tov(struct bfa_ioim_s *ioim);
+
+void bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim,
+ struct bfa_meminfo_s *minfo);
+void bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim);
+void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+void bfa_tskim_iodone(struct bfa_tskim_s *tskim);
+void bfa_tskim_iocdisable(struct bfa_tskim_s *tskim);
+void bfa_tskim_cleanup(struct bfa_tskim_s *tskim);
+
+void bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len);
+void bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim,
+ struct bfa_meminfo_s *minfo);
+void bfa_itnim_detach(struct bfa_fcpim_mod_s *fcpim);
+void bfa_itnim_iocdisable(struct bfa_itnim_s *itnim);
+void bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+void bfa_itnim_iodone(struct bfa_itnim_s *itnim);
+void bfa_itnim_tskdone(struct bfa_itnim_s *itnim);
+bfa_boolean_t bfa_itnim_hold_io(struct bfa_itnim_s *itnim);
+
+#endif /* __BFA_FCPIM_PRIV_H__ */
+
diff --git a/drivers/scsi/bfa/bfa_fcport.c b/drivers/scsi/bfa/bfa_fcport.c
new file mode 100644
index 000000000000..aef648b55dfc
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcport.c
@@ -0,0 +1,1668 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_pport.h>
+#include <cs/bfa_debug.h>
+#include <aen/bfa_aen.h>
+#include <cs/bfa_plog.h>
+#include <aen/bfa_aen_port.h>
+
+BFA_TRC_FILE(HAL, PPORT);
+BFA_MODULE(pport);
+
+#define bfa_pport_callback(__pport, __event) do { \
+ if ((__pport)->bfa->fcs) { \
+ (__pport)->event_cbfn((__pport)->event_cbarg, (__event)); \
+ } else { \
+ (__pport)->hcb_event = (__event); \
+ bfa_cb_queue((__pport)->bfa, &(__pport)->hcb_qe, \
+ __bfa_cb_port_event, (__pport)); \
+ } \
+} while (0)
+
+/*
+ * The port is considered disabled if corresponding physical port or IOC are
+ * disabled explicitly
+ */
+#define BFA_PORT_IS_DISABLED(bfa) \
+ ((bfa_pport_is_disabled(bfa) == BFA_TRUE) || \
+ (bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE))
+
+/*
+ * forward declarations
+ */
+static bfa_boolean_t bfa_pport_send_enable(struct bfa_pport_s *port);
+static bfa_boolean_t bfa_pport_send_disable(struct bfa_pport_s *port);
+static void bfa_pport_update_linkinfo(struct bfa_pport_s *pport);
+static void bfa_pport_reset_linkinfo(struct bfa_pport_s *pport);
+static void bfa_pport_set_wwns(struct bfa_pport_s *port);
+static void __bfa_cb_port_event(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_port_stats_clr(void *cbarg, bfa_boolean_t complete);
+static void bfa_port_stats_timeout(void *cbarg);
+static void bfa_port_stats_clr_timeout(void *cbarg);
+
+/**
+ * bfa_pport_private
+ */
+
+/**
+ * BFA port state machine events
+ */
+enum bfa_pport_sm_event {
+ BFA_PPORT_SM_START = 1, /* start port state machine */
+ BFA_PPORT_SM_STOP = 2, /* stop port state machine */
+ BFA_PPORT_SM_ENABLE = 3, /* enable port */
+ BFA_PPORT_SM_DISABLE = 4, /* disable port state machine */
+ BFA_PPORT_SM_FWRSP = 5, /* firmware enable/disable rsp */
+ BFA_PPORT_SM_LINKUP = 6, /* firmware linkup event */
+ BFA_PPORT_SM_LINKDOWN = 7, /* firmware linkup down */
+ BFA_PPORT_SM_QRESUME = 8, /* CQ space available */
+ BFA_PPORT_SM_HWFAIL = 9, /* IOC h/w failure */
+};
+
+static void bfa_pport_sm_uninit(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_enabling_qwait(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_enabling(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_linkdown(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_linkup(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_disabling(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_disabling_qwait(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_disabled(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_stopped(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_iocdown(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+static void bfa_pport_sm_iocfail(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event);
+
+static struct bfa_sm_table_s hal_pport_sm_table[] = {
+ {BFA_SM(bfa_pport_sm_uninit), BFA_PPORT_ST_UNINIT},
+ {BFA_SM(bfa_pport_sm_enabling_qwait), BFA_PPORT_ST_ENABLING_QWAIT},
+ {BFA_SM(bfa_pport_sm_enabling), BFA_PPORT_ST_ENABLING},
+ {BFA_SM(bfa_pport_sm_linkdown), BFA_PPORT_ST_LINKDOWN},
+ {BFA_SM(bfa_pport_sm_linkup), BFA_PPORT_ST_LINKUP},
+ {BFA_SM(bfa_pport_sm_disabling_qwait),
+ BFA_PPORT_ST_DISABLING_QWAIT},
+ {BFA_SM(bfa_pport_sm_disabling), BFA_PPORT_ST_DISABLING},
+ {BFA_SM(bfa_pport_sm_disabled), BFA_PPORT_ST_DISABLED},
+ {BFA_SM(bfa_pport_sm_stopped), BFA_PPORT_ST_STOPPED},
+ {BFA_SM(bfa_pport_sm_iocdown), BFA_PPORT_ST_IOCDOWN},
+ {BFA_SM(bfa_pport_sm_iocfail), BFA_PPORT_ST_IOCDOWN},
+};
+
+static void
+bfa_pport_aen_post(struct bfa_pport_s *pport, enum bfa_port_aen_event event)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = pport->bfa->logm;
+ wwn_t pwwn = pport->pwwn;
+ char pwwn_ptr[BFA_STRING_32];
+ struct bfa_ioc_attr_s ioc_attr;
+
+ wwn2str(pwwn_ptr, pwwn);
+ switch (event) {
+ case BFA_PORT_AEN_ONLINE:
+ bfa_log(logmod, BFA_AEN_PORT_ONLINE, pwwn_ptr);
+ break;
+ case BFA_PORT_AEN_OFFLINE:
+ bfa_log(logmod, BFA_AEN_PORT_OFFLINE, pwwn_ptr);
+ break;
+ case BFA_PORT_AEN_ENABLE:
+ bfa_log(logmod, BFA_AEN_PORT_ENABLE, pwwn_ptr);
+ break;
+ case BFA_PORT_AEN_DISABLE:
+ bfa_log(logmod, BFA_AEN_PORT_DISABLE, pwwn_ptr);
+ break;
+ case BFA_PORT_AEN_DISCONNECT:
+ bfa_log(logmod, BFA_AEN_PORT_DISCONNECT, pwwn_ptr);
+ break;
+ case BFA_PORT_AEN_QOS_NEG:
+ bfa_log(logmod, BFA_AEN_PORT_QOS_NEG, pwwn_ptr);
+ break;
+ default:
+ break;
+ }
+
+ bfa_ioc_get_attr(&pport->bfa->ioc, &ioc_attr);
+ aen_data.port.ioc_type = ioc_attr.ioc_type;
+ aen_data.port.pwwn = pwwn;
+}
+
+static void
+bfa_pport_sm_uninit(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_START:
+ /**
+ * Start event after IOC is configured and BFA is started.
+ */
+ if (bfa_pport_send_enable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ /**
+ * Port is persistently configured to be in enabled state. Do
+ * not change state. Port enabling is done when START event is
+ * received.
+ */
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ /**
+ * If a port is persistently configured to be disabled, the
+ * first event will a port disable request.
+ */
+ bfa_sm_set_state(pport, bfa_pport_sm_disabled);
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_enabling_qwait(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_QRESUME:
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ bfa_pport_send_enable(pport);
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_reqq_wcancel(&pport->reqq_wait);
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ /**
+ * Already enable is in progress.
+ */
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ /**
+ * Just send disable request to firmware when room becomes
+ * available in request queue.
+ */
+ bfa_sm_set_state(pport, bfa_pport_sm_disabled);
+ bfa_reqq_wcancel(&pport->reqq_wait);
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+ break;
+
+ case BFA_PPORT_SM_LINKUP:
+ case BFA_PPORT_SM_LINKDOWN:
+ /**
+ * Possible to get link events when doing back-to-back
+ * enable/disables.
+ */
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_reqq_wcancel(&pport->reqq_wait);
+ bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_enabling(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_FWRSP:
+ case BFA_PPORT_SM_LINKDOWN:
+ bfa_sm_set_state(pport, bfa_pport_sm_linkdown);
+ break;
+
+ case BFA_PPORT_SM_LINKUP:
+ bfa_pport_update_linkinfo(pport);
+ bfa_sm_set_state(pport, bfa_pport_sm_linkup);
+
+ bfa_assert(pport->event_cbfn);
+ bfa_pport_callback(pport, BFA_PPORT_LINKUP);
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ /**
+ * Already being enabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ if (bfa_pport_send_disable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait);
+
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_linkdown(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_LINKUP:
+ bfa_pport_update_linkinfo(pport);
+ bfa_sm_set_state(pport, bfa_pport_sm_linkup);
+ bfa_assert(pport->event_cbfn);
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkup");
+ bfa_pport_callback(pport, BFA_PPORT_LINKUP);
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_ONLINE);
+ /**
+ * If QoS is enabled and it is not online,
+ * Send a separate event.
+ */
+ if ((pport->cfg.qos_enabled)
+ && (bfa_os_ntohl(pport->qos_attr.state) != BFA_QOS_ONLINE))
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_QOS_NEG);
+
+ break;
+
+ case BFA_PPORT_SM_LINKDOWN:
+ /**
+ * Possible to get link down event.
+ */
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ /**
+ * Already enabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ if (bfa_pport_send_disable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait);
+
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_linkup(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_ENABLE:
+ /**
+ * Already enabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ if (bfa_pport_send_disable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling_qwait);
+
+ bfa_pport_reset_linkinfo(pport);
+ bfa_pport_callback(pport, BFA_PPORT_LINKDOWN);
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_DISABLE, 0, "Port Disable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISABLE);
+ break;
+
+ case BFA_PPORT_SM_LINKDOWN:
+ bfa_sm_set_state(pport, bfa_pport_sm_linkdown);
+ bfa_pport_reset_linkinfo(pport);
+ 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))
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
+ 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))
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
+ 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))
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_OFFLINE);
+ else
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_DISCONNECT);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_disabling_qwait(struct bfa_pport_s *pport,
+ enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_QRESUME:
+ bfa_sm_set_state(pport, bfa_pport_sm_disabling);
+ bfa_pport_send_disable(pport);
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ bfa_reqq_wcancel(&pport->reqq_wait);
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ /**
+ * Already being disabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_LINKUP:
+ case BFA_PPORT_SM_LINKDOWN:
+ /**
+ * Possible to get link events when doing back-to-back
+ * enable/disables.
+ */
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
+ bfa_reqq_wcancel(&pport->reqq_wait);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_disabling(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_FWRSP:
+ bfa_sm_set_state(pport, bfa_pport_sm_disabled);
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ /**
+ * Already being disabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ if (bfa_pport_send_enable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_ENABLE);
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ break;
+
+ case BFA_PPORT_SM_LINKUP:
+ case BFA_PPORT_SM_LINKDOWN:
+ /**
+ * Possible to get link events when doing back-to-back
+ * enable/disables.
+ */
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_disabled(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_START:
+ /**
+ * Ignore start event for a port that is disabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_STOP:
+ bfa_sm_set_state(pport, bfa_pport_sm_stopped);
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ if (bfa_pport_send_enable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+
+ bfa_plog_str(pport->bfa->plog, BFA_PL_MID_HAL,
+ BFA_PL_EID_PORT_ENABLE, 0, "Port Enable");
+ bfa_pport_aen_post(pport, BFA_PORT_AEN_ENABLE);
+ break;
+
+ case BFA_PPORT_SM_DISABLE:
+ /**
+ * Already disabled.
+ */
+ break;
+
+ case BFA_PPORT_SM_HWFAIL:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocfail);
+ break;
+
+ default:
+ bfa_sm_fault(pport->bfa, event);
+ }
+}
+
+static void
+bfa_pport_sm_stopped(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_START:
+ if (bfa_pport_send_enable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+ break;
+
+ default:
+ /**
+ * Ignore all other events.
+ */
+ ;
+ }
+}
+
+/**
+ * Port is enabled. IOC is down/failed.
+ */
+static void
+bfa_pport_sm_iocdown(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_START:
+ if (bfa_pport_send_enable(pport))
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling);
+ else
+ bfa_sm_set_state(pport, bfa_pport_sm_enabling_qwait);
+ break;
+
+ default:
+ /**
+ * Ignore all events.
+ */
+ ;
+ }
+}
+
+/**
+ * Port is disabled. IOC is down/failed.
+ */
+static void
+bfa_pport_sm_iocfail(struct bfa_pport_s *pport, enum bfa_pport_sm_event event)
+{
+ bfa_trc(pport->bfa, event);
+
+ switch (event) {
+ case BFA_PPORT_SM_START:
+ bfa_sm_set_state(pport, bfa_pport_sm_disabled);
+ break;
+
+ case BFA_PPORT_SM_ENABLE:
+ bfa_sm_set_state(pport, bfa_pport_sm_iocdown);
+ break;
+
+ default:
+ /**
+ * Ignore all events.
+ */
+ ;
+ }
+}
+
+
+
+/**
+ * bfa_pport_private
+ */
+
+static void
+__bfa_cb_port_event(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_pport_s *pport = cbarg;
+
+ if (complete)
+ pport->event_cbfn(pport->event_cbarg, pport->hcb_event);
+}
+
+#define PPORT_STATS_DMA_SZ (BFA_ROUNDUP(sizeof(union bfa_pport_stats_u), \
+ BFA_CACHELINE_SZ))
+
+static void
+bfa_pport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
+ u32 *dm_len)
+{
+ *dm_len += PPORT_STATS_DMA_SZ;
+}
+
+static void
+bfa_pport_qresume(void *cbarg)
+{
+ struct bfa_pport_s *port = cbarg;
+
+ bfa_sm_send_event(port, BFA_PPORT_SM_QRESUME);
+}
+
+static void
+bfa_pport_mem_claim(struct bfa_pport_s *pport, struct bfa_meminfo_s *meminfo)
+{
+ u8 *dm_kva;
+ u64 dm_pa;
+
+ dm_kva = bfa_meminfo_dma_virt(meminfo);
+ dm_pa = bfa_meminfo_dma_phys(meminfo);
+
+ pport->stats_kva = dm_kva;
+ pport->stats_pa = dm_pa;
+ pport->stats = (union bfa_pport_stats_u *)dm_kva;
+
+ dm_kva += PPORT_STATS_DMA_SZ;
+ dm_pa += PPORT_STATS_DMA_SZ;
+
+ bfa_meminfo_dma_virt(meminfo) = dm_kva;
+ bfa_meminfo_dma_phys(meminfo) = dm_pa;
+}
+
+/**
+ * Memory initialization.
+ */
+static void
+bfa_pport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+ struct bfa_pport_cfg_s *port_cfg = &pport->cfg;
+
+ bfa_os_memset(pport, 0, sizeof(struct bfa_pport_s));
+ pport->bfa = bfa;
+
+ bfa_pport_mem_claim(pport, meminfo);
+
+ bfa_sm_set_state(pport, bfa_pport_sm_uninit);
+
+ /**
+ * initialize and set default configuration
+ */
+ port_cfg->topology = BFA_PPORT_TOPOLOGY_P2P;
+ port_cfg->speed = BFA_PPORT_SPEED_AUTO;
+ port_cfg->trunked = BFA_FALSE;
+ port_cfg->maxfrsize = 0;
+
+ port_cfg->trl_def_speed = BFA_PPORT_SPEED_1GBPS;
+
+ bfa_reqq_winit(&pport->reqq_wait, bfa_pport_qresume, pport);
+}
+
+static void
+bfa_pport_initdone(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ /**
+ * Initialize port attributes from IOC hardware data.
+ */
+ bfa_pport_set_wwns(pport);
+ if (pport->cfg.maxfrsize == 0)
+ pport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc);
+ pport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc);
+ pport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc);
+
+ bfa_assert(pport->cfg.maxfrsize);
+ bfa_assert(pport->cfg.rx_bbcredit);
+ bfa_assert(pport->speed_sup);
+}
+
+static void
+bfa_pport_detach(struct bfa_s *bfa)
+{
+}
+
+/**
+ * Called when IOC is ready.
+ */
+static void
+bfa_pport_start(struct bfa_s *bfa)
+{
+ bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_START);
+}
+
+/**
+ * Called before IOC is stopped.
+ */
+static void
+bfa_pport_stop(struct bfa_s *bfa)
+{
+ bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_STOP);
+}
+
+/**
+ * Called when IOC failure is detected.
+ */
+static void
+bfa_pport_iocdisable(struct bfa_s *bfa)
+{
+ bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_HWFAIL);
+}
+
+static void
+bfa_pport_update_linkinfo(struct bfa_pport_s *pport)
+{
+ struct bfi_pport_event_s *pevent = pport->event_arg.i2hmsg.event;
+
+ pport->speed = pevent->link_state.speed;
+ pport->topology = pevent->link_state.topology;
+
+ if (pport->topology == BFA_PPORT_TOPOLOGY_LOOP)
+ pport->myalpa = pevent->link_state.tl.loop_info.myalpa;
+
+ /*
+ * QoS Details
+ */
+ bfa_os_assign(pport->qos_attr, pevent->link_state.qos_attr);
+ bfa_os_assign(pport->qos_vc_attr, pevent->link_state.qos_vc_attr);
+
+ bfa_trc(pport->bfa, pport->speed);
+ bfa_trc(pport->bfa, pport->topology);
+}
+
+static void
+bfa_pport_reset_linkinfo(struct bfa_pport_s *pport)
+{
+ pport->speed = BFA_PPORT_SPEED_UNKNOWN;
+ pport->topology = BFA_PPORT_TOPOLOGY_NONE;
+}
+
+/**
+ * Send port enable message to firmware.
+ */
+static bfa_boolean_t
+bfa_pport_send_enable(struct bfa_pport_s *port)
+{
+ struct bfi_pport_enable_req_s *m;
+
+ /**
+ * Increment message tag before queue check, so that responses to old
+ * requests are discarded.
+ */
+ port->msgtag++;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+ if (!m) {
+ bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_ENABLE_REQ,
+ bfa_lpuid(port->bfa));
+ m->nwwn = port->nwwn;
+ m->pwwn = port->pwwn;
+ m->port_cfg = port->cfg;
+ m->msgtag = port->msgtag;
+ m->port_cfg.maxfrsize = bfa_os_htons(port->cfg.maxfrsize);
+ bfa_dma_be_addr_set(m->stats_dma_addr, port->stats_pa);
+ bfa_trc(port->bfa, m->stats_dma_addr.a32.addr_lo);
+ bfa_trc(port->bfa, m->stats_dma_addr.a32.addr_hi);
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+ return BFA_TRUE;
+}
+
+/**
+ * Send port disable message to firmware.
+ */
+static bfa_boolean_t
+bfa_pport_send_disable(struct bfa_pport_s *port)
+{
+ bfi_pport_disable_req_t *m;
+
+ /**
+ * Increment message tag before queue check, so that responses to old
+ * requests are discarded.
+ */
+ port->msgtag++;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+ if (!m) {
+ bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_DISABLE_REQ,
+ bfa_lpuid(port->bfa));
+ m->msgtag = port->msgtag;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+
+ return BFA_TRUE;
+}
+
+static void
+bfa_pport_set_wwns(struct bfa_pport_s *port)
+{
+ port->pwwn = bfa_ioc_get_pwwn(&port->bfa->ioc);
+ port->nwwn = bfa_ioc_get_nwwn(&port->bfa->ioc);
+
+ bfa_trc(port->bfa, port->pwwn);
+ bfa_trc(port->bfa, port->nwwn);
+}
+
+static void
+bfa_port_send_txcredit(void *port_cbarg)
+{
+
+ struct bfa_pport_s *port = port_cbarg;
+ struct bfi_pport_set_svc_params_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+ if (!m) {
+ bfa_trc(port->bfa, port->cfg.tx_bbcredit);
+ return;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_SET_SVC_PARAMS_REQ,
+ bfa_lpuid(port->bfa));
+ m->tx_bbcredit = bfa_os_htons((u16) port->cfg.tx_bbcredit);
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+}
+
+
+
+/**
+ * bfa_pport_public
+ */
+
+/**
+ * Firmware message handler.
+ */
+void
+bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+ union bfi_pport_i2h_msg_u i2hmsg;
+
+ i2hmsg.msg = msg;
+ pport->event_arg.i2hmsg = i2hmsg;
+
+ switch (msg->mhdr.msg_id) {
+ case BFI_PPORT_I2H_ENABLE_RSP:
+ if (pport->msgtag == i2hmsg.enable_rsp->msgtag)
+ bfa_sm_send_event(pport, BFA_PPORT_SM_FWRSP);
+ break;
+
+ case BFI_PPORT_I2H_DISABLE_RSP:
+ if (pport->msgtag == i2hmsg.enable_rsp->msgtag)
+ bfa_sm_send_event(pport, BFA_PPORT_SM_FWRSP);
+ break;
+
+ case BFI_PPORT_I2H_EVENT:
+ switch (i2hmsg.event->link_state.linkstate) {
+ case BFA_PPORT_LINKUP:
+ bfa_sm_send_event(pport, BFA_PPORT_SM_LINKUP);
+ break;
+ case BFA_PPORT_LINKDOWN:
+ bfa_sm_send_event(pport, BFA_PPORT_SM_LINKDOWN);
+ break;
+ case BFA_PPORT_TRUNK_LINKDOWN:
+ /** todo: event notification */
+ break;
+ }
+ break;
+
+ case BFI_PPORT_I2H_GET_STATS_RSP:
+ case BFI_PPORT_I2H_GET_QOS_STATS_RSP:
+ /*
+ * check for timer pop before processing the rsp
+ */
+ if (pport->stats_busy == BFA_FALSE
+ || pport->stats_status == BFA_STATUS_ETIMER)
+ break;
+
+ bfa_timer_stop(&pport->timer);
+ pport->stats_status = i2hmsg.getstats_rsp->status;
+ bfa_cb_queue(pport->bfa, &pport->hcb_qe, __bfa_cb_port_stats,
+ pport);
+ break;
+ case BFI_PPORT_I2H_CLEAR_STATS_RSP:
+ case BFI_PPORT_I2H_CLEAR_QOS_STATS_RSP:
+ /*
+ * check for timer pop before processing the rsp
+ */
+ if (pport->stats_busy == BFA_FALSE
+ || pport->stats_status == BFA_STATUS_ETIMER)
+ break;
+
+ bfa_timer_stop(&pport->timer);
+ pport->stats_status = BFA_STATUS_OK;
+ bfa_cb_queue(pport->bfa, &pport->hcb_qe,
+ __bfa_cb_port_stats_clr, pport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_pport_api
+ */
+
+/**
+ * Registered callback for port events.
+ */
+void
+bfa_pport_event_register(struct bfa_s *bfa,
+ void (*cbfn) (void *cbarg, bfa_pport_event_t event),
+ void *cbarg)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ pport->event_cbfn = cbfn;
+ pport->event_cbarg = cbarg;
+}
+
+bfa_status_t
+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;
+ else if (bfa_sm_cmp_state
+ (BFA_PORT_MOD(bfa), bfa_pport_sm_disabling_qwait))
+ return BFA_STATUS_DEVBUSY;
+
+ bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_ENABLE);
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_pport_disable(struct bfa_s *bfa)
+{
+ bfa_sm_send_event(BFA_PORT_MOD(bfa), BFA_PPORT_SM_DISABLE);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Configure port speed.
+ */
+bfa_status_t
+bfa_pport_cfg_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, speed);
+
+ if ((speed != BFA_PPORT_SPEED_AUTO) && (speed > pport->speed_sup)) {
+ bfa_trc(bfa, pport->speed_sup);
+ return BFA_STATUS_UNSUPP_SPEED;
+ }
+
+ pport->cfg.speed = speed;
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Get current speed.
+ */
+enum bfa_pport_speed
+bfa_pport_get_speed(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->speed;
+}
+
+/**
+ * Configure port topology.
+ */
+bfa_status_t
+bfa_pport_cfg_topology(struct bfa_s *bfa, enum bfa_pport_topology topology)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, topology);
+ bfa_trc(bfa, pport->cfg.topology);
+
+ switch (topology) {
+ case BFA_PPORT_TOPOLOGY_P2P:
+ case BFA_PPORT_TOPOLOGY_LOOP:
+ case BFA_PPORT_TOPOLOGY_AUTO:
+ break;
+
+ default:
+ return BFA_STATUS_EINVAL;
+ }
+
+ pport->cfg.topology = topology;
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Get current topology.
+ */
+enum bfa_pport_topology
+bfa_pport_get_topology(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->topology;
+}
+
+bfa_status_t
+bfa_pport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, alpa);
+ bfa_trc(bfa, pport->cfg.cfg_hardalpa);
+ bfa_trc(bfa, pport->cfg.hardalpa);
+
+ pport->cfg.cfg_hardalpa = BFA_TRUE;
+ pport->cfg.hardalpa = alpa;
+
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_pport_clr_hardalpa(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, pport->cfg.cfg_hardalpa);
+ bfa_trc(bfa, pport->cfg.hardalpa);
+
+ pport->cfg.cfg_hardalpa = BFA_FALSE;
+ return BFA_STATUS_OK;
+}
+
+bfa_boolean_t
+bfa_pport_get_hardalpa(struct bfa_s *bfa, u8 *alpa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ *alpa = port->cfg.hardalpa;
+ return port->cfg.cfg_hardalpa;
+}
+
+u8
+bfa_pport_get_myalpa(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->myalpa;
+}
+
+bfa_status_t
+bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, maxfrsize);
+ bfa_trc(bfa, pport->cfg.maxfrsize);
+
+ /*
+ * with in range
+ */
+ if ((maxfrsize > FC_MAX_PDUSZ) || (maxfrsize < FC_MIN_PDUSZ))
+ 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;
+
+ pport->cfg.maxfrsize = maxfrsize;
+ return BFA_STATUS_OK;
+}
+
+u16
+bfa_pport_get_maxfrsize(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->cfg.maxfrsize;
+}
+
+u32
+bfa_pport_mypid(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->mypid;
+}
+
+u8
+bfa_pport_get_rx_bbcredit(struct bfa_s *bfa)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ return port->cfg.rx_bbcredit;
+}
+
+void
+bfa_pport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ port->cfg.tx_bbcredit = (u8) tx_bbcredit;
+ bfa_port_send_txcredit(port);
+}
+
+/**
+ * Get port attributes.
+ */
+
+wwn_t
+bfa_pport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+ if (node)
+ return pport->nwwn;
+ else
+ return pport->pwwn;
+}
+
+void
+bfa_pport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_os_memset(attr, 0, sizeof(struct bfa_pport_attr_s));
+
+ attr->nwwn = pport->nwwn;
+ attr->pwwn = pport->pwwn;
+
+ bfa_os_memcpy(&attr->pport_cfg, &pport->cfg,
+ sizeof(struct bfa_pport_cfg_s));
+ /*
+ * speed attributes
+ */
+ attr->pport_cfg.speed = pport->cfg.speed;
+ attr->speed_supported = pport->speed_sup;
+ attr->speed = pport->speed;
+ attr->cos_supported = FC_CLASS_3;
+
+ /*
+ * topology attributes
+ */
+ attr->pport_cfg.topology = pport->cfg.topology;
+ attr->topology = pport->topology;
+
+ /*
+ * beacon attributes
+ */
+ attr->beacon = pport->beacon;
+ attr->link_e2e_beacon = pport->link_e2e_beacon;
+ attr->plog_enabled = bfa_plog_get_setting(pport->bfa->plog);
+
+ attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa);
+ attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa);
+ attr->port_state = bfa_sm_to_state(hal_pport_sm_table, pport->sm);
+ if (bfa_ioc_is_disabled(&pport->bfa->ioc))
+ attr->port_state = BFA_PPORT_ST_IOCDIS;
+ else if (bfa_ioc_fw_mismatch(&pport->bfa->ioc))
+ attr->port_state = BFA_PPORT_ST_FWMISMATCH;
+}
+
+static void
+bfa_port_stats_query(void *cbarg)
+{
+ struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
+ bfi_pport_get_stats_req_t *msg;
+
+ msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+
+ if (!msg) {
+ port->stats_qfull = BFA_TRUE;
+ bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_stats_query,
+ port);
+ bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait);
+ return;
+ }
+ port->stats_qfull = BFA_FALSE;
+
+ bfa_os_memset(msg, 0, sizeof(bfi_pport_get_stats_req_t));
+ bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_GET_STATS_REQ,
+ bfa_lpuid(port->bfa));
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+
+ return;
+}
+
+static void
+bfa_port_stats_clear(void *cbarg)
+{
+ struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
+ bfi_pport_clear_stats_req_t *msg;
+
+ msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+
+ if (!msg) {
+ port->stats_qfull = BFA_TRUE;
+ bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_stats_clear,
+ port);
+ bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait);
+ return;
+ }
+ port->stats_qfull = BFA_FALSE;
+
+ bfa_os_memset(msg, 0, sizeof(bfi_pport_clear_stats_req_t));
+ bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_CLEAR_STATS_REQ,
+ bfa_lpuid(port->bfa));
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+ return;
+}
+
+static void
+bfa_port_qos_stats_clear(void *cbarg)
+{
+ struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
+ bfi_pport_clear_qos_stats_req_t *msg;
+
+ msg = bfa_reqq_next(port->bfa, BFA_REQQ_PORT);
+
+ if (!msg) {
+ port->stats_qfull = BFA_TRUE;
+ bfa_reqq_winit(&port->stats_reqq_wait, bfa_port_qos_stats_clear,
+ port);
+ bfa_reqq_wait(port->bfa, BFA_REQQ_PORT, &port->stats_reqq_wait);
+ return;
+ }
+ port->stats_qfull = BFA_FALSE;
+
+ bfa_os_memset(msg, 0, sizeof(bfi_pport_clear_qos_stats_req_t));
+ bfi_h2i_set(msg->mh, BFI_MC_FC_PORT, BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ,
+ bfa_lpuid(port->bfa));
+ bfa_reqq_produce(port->bfa, BFA_REQQ_PORT);
+ return;
+}
+
+static void
+bfa_pport_stats_swap(union bfa_pport_stats_u *d, union bfa_pport_stats_u *s)
+{
+ u32 *dip = (u32 *) d;
+ u32 *sip = (u32 *) s;
+ int i;
+
+ /*
+ * Do 64 bit fields swap first
+ */
+ for (i = 0;
+ i <
+ ((sizeof(union bfa_pport_stats_u) -
+ sizeof(struct bfa_qos_stats_s)) / sizeof(u32)); i = i + 2) {
+#ifdef __BIGENDIAN
+ dip[i] = bfa_os_ntohl(sip[i]);
+ dip[i + 1] = bfa_os_ntohl(sip[i + 1]);
+#else
+ dip[i] = bfa_os_ntohl(sip[i + 1]);
+ dip[i + 1] = bfa_os_ntohl(sip[i]);
+#endif
+ }
+
+ /*
+ * Now swap the 32 bit fields
+ */
+ for (; i < (sizeof(union bfa_pport_stats_u) / sizeof(u32)); ++i)
+ dip[i] = bfa_os_ntohl(sip[i]);
+}
+
+static void
+__bfa_cb_port_stats_clr(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_pport_s *port = cbarg;
+
+ if (complete) {
+ port->stats_cbfn(port->stats_cbarg, port->stats_status);
+ } else {
+ port->stats_busy = BFA_FALSE;
+ port->stats_status = BFA_STATUS_OK;
+ }
+}
+
+static void
+bfa_port_stats_clr_timeout(void *cbarg)
+{
+ struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
+
+ bfa_trc(port->bfa, port->stats_qfull);
+
+ if (port->stats_qfull) {
+ bfa_reqq_wcancel(&port->stats_reqq_wait);
+ port->stats_qfull = BFA_FALSE;
+ }
+
+ port->stats_status = BFA_STATUS_ETIMER;
+ bfa_cb_queue(port->bfa, &port->hcb_qe, __bfa_cb_port_stats_clr, port);
+}
+
+static void
+__bfa_cb_port_stats(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_pport_s *port = cbarg;
+
+ if (complete) {
+ if (port->stats_status == BFA_STATUS_OK)
+ bfa_pport_stats_swap(port->stats_ret, port->stats);
+ port->stats_cbfn(port->stats_cbarg, port->stats_status);
+ } else {
+ port->stats_busy = BFA_FALSE;
+ port->stats_status = BFA_STATUS_OK;
+ }
+}
+
+static void
+bfa_port_stats_timeout(void *cbarg)
+{
+ struct bfa_pport_s *port = (struct bfa_pport_s *)cbarg;
+
+ bfa_trc(port->bfa, port->stats_qfull);
+
+ if (port->stats_qfull) {
+ bfa_reqq_wcancel(&port->stats_reqq_wait);
+ port->stats_qfull = BFA_FALSE;
+ }
+
+ port->stats_status = BFA_STATUS_ETIMER;
+ bfa_cb_queue(port->bfa, &port->hcb_qe, __bfa_cb_port_stats, port);
+}
+
+#define BFA_PORT_STATS_TOV 1000
+
+/**
+ * Fetch port attributes.
+ */
+bfa_status_t
+bfa_pport_get_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
+ bfa_cb_pport_t cbfn, void *cbarg)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ if (port->stats_busy) {
+ bfa_trc(bfa, port->stats_busy);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ port->stats_busy = BFA_TRUE;
+ port->stats_ret = stats;
+ port->stats_cbfn = cbfn;
+ port->stats_cbarg = cbarg;
+
+ bfa_port_stats_query(port);
+
+ bfa_timer_start(bfa, &port->timer, bfa_port_stats_timeout, port,
+ BFA_PORT_STATS_TOV);
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ if (port->stats_busy) {
+ bfa_trc(bfa, port->stats_busy);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ port->stats_busy = BFA_TRUE;
+ port->stats_cbfn = cbfn;
+ port->stats_cbarg = cbarg;
+
+ bfa_port_stats_clear(port);
+
+ bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port,
+ BFA_PORT_STATS_TOV);
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_pport_trunk_enable(struct bfa_s *bfa, u8 bitmap)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, bitmap);
+ bfa_trc(bfa, pport->cfg.trunked);
+ bfa_trc(bfa, pport->cfg.trunk_ports);
+
+ if (!bitmap || (bitmap & (bitmap - 1)))
+ return BFA_STATUS_EINVAL;
+
+ pport->cfg.trunked = BFA_TRUE;
+ pport->cfg.trunk_ports = bitmap;
+
+ return BFA_STATUS_OK;
+}
+
+void
+bfa_pport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ qos_attr->state = bfa_os_ntohl(pport->qos_attr.state);
+ qos_attr->total_bb_cr = bfa_os_ntohl(pport->qos_attr.total_bb_cr);
+}
+
+void
+bfa_pport_qos_get_vc_attr(struct bfa_s *bfa,
+ struct bfa_qos_vc_attr_s *qos_vc_attr)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+ struct bfa_qos_vc_attr_s *bfa_vc_attr = &pport->qos_vc_attr;
+ u32 i = 0;
+
+ qos_vc_attr->total_vc_count = bfa_os_ntohs(bfa_vc_attr->total_vc_count);
+ qos_vc_attr->shared_credit = bfa_os_ntohs(bfa_vc_attr->shared_credit);
+ qos_vc_attr->elp_opmode_flags =
+ bfa_os_ntohl(bfa_vc_attr->elp_opmode_flags);
+
+ /*
+ * Individual VC info
+ */
+ while (i < qos_vc_attr->total_vc_count) {
+ qos_vc_attr->vc_info[i].vc_credit =
+ bfa_vc_attr->vc_info[i].vc_credit;
+ qos_vc_attr->vc_info[i].borrow_credit =
+ bfa_vc_attr->vc_info[i].borrow_credit;
+ qos_vc_attr->vc_info[i].priority =
+ bfa_vc_attr->vc_info[i].priority;
+ ++i;
+ }
+}
+
+/**
+ * Fetch QoS Stats.
+ */
+bfa_status_t
+bfa_pport_get_qos_stats(struct bfa_s *bfa, union bfa_pport_stats_u *stats,
+ bfa_cb_pport_t cbfn, void *cbarg)
+{
+ /*
+ * QoS stats is embedded in port stats
+ */
+ return bfa_pport_get_stats(bfa, stats, cbfn, cbarg);
+}
+
+bfa_status_t
+bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn, void *cbarg)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ if (port->stats_busy) {
+ bfa_trc(bfa, port->stats_busy);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ port->stats_busy = BFA_TRUE;
+ port->stats_cbfn = cbfn;
+ port->stats_cbarg = cbarg;
+
+ bfa_port_qos_stats_clear(port);
+
+ bfa_timer_start(bfa, &port->timer, bfa_port_stats_clr_timeout, port,
+ BFA_PORT_STATS_TOV);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Fetch port attributes.
+ */
+bfa_status_t
+bfa_pport_trunk_disable(struct bfa_s *bfa)
+{
+ return BFA_STATUS_OK;
+}
+
+bfa_boolean_t
+bfa_pport_trunk_query(struct bfa_s *bfa, u32 *bitmap)
+{
+ struct bfa_pport_s *port = BFA_PORT_MOD(bfa);
+
+ *bitmap = port->cfg.trunk_ports;
+ return port->cfg.trunked;
+}
+
+bfa_boolean_t
+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;
+
+}
+
+bfa_boolean_t
+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;
+
+}
+
+void
+bfa_pport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, on_off);
+ bfa_trc(bfa, pport->cfg.qos_enabled);
+
+ pport->cfg.qos_enabled = on_off;
+}
+
+void
+bfa_pport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, on_off);
+ bfa_trc(bfa, pport->cfg.ratelimit);
+
+ pport->cfg.ratelimit = on_off;
+ if (pport->cfg.trl_def_speed == BFA_PPORT_SPEED_UNKNOWN)
+ pport->cfg.trl_def_speed = BFA_PPORT_SPEED_1GBPS;
+}
+
+/**
+ * Configure default minimum ratelim speed
+ */
+bfa_status_t
+bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa, enum bfa_pport_speed speed)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, speed);
+
+ /*
+ * Auto and speeds greater than the supported speed, are invalid
+ */
+ if ((speed == BFA_PPORT_SPEED_AUTO) || (speed > pport->speed_sup)) {
+ bfa_trc(bfa, pport->speed_sup);
+ return BFA_STATUS_UNSUPP_SPEED;
+ }
+
+ pport->cfg.trl_def_speed = speed;
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Get default minimum ratelim speed
+ */
+enum bfa_pport_speed
+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;
+
+}
+
+void
+bfa_pport_busy(struct bfa_s *bfa, bfa_boolean_t status)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, status);
+ bfa_trc(bfa, pport->diag_busy);
+
+ pport->diag_busy = status;
+}
+
+void
+bfa_pport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon,
+ bfa_boolean_t link_e2e_beacon)
+{
+ struct bfa_pport_s *pport = BFA_PORT_MOD(bfa);
+
+ bfa_trc(bfa, beacon);
+ bfa_trc(bfa, link_e2e_beacon);
+ bfa_trc(bfa, pport->beacon);
+ bfa_trc(bfa, pport->link_e2e_beacon);
+
+ pport->beacon = beacon;
+ pport->link_e2e_beacon = link_e2e_beacon;
+}
+
+bfa_boolean_t
+bfa_pport_is_linkup(struct bfa_s *bfa)
+{
+ return bfa_sm_cmp_state(BFA_PORT_MOD(bfa), bfa_pport_sm_linkup);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcs.c b/drivers/scsi/bfa/bfa_fcs.c
new file mode 100644
index 000000000000..7cb39a306ea9
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcs.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcs.c BFA FCS main
+ */
+
+#include <fcs/bfa_fcs.h>
+#include "fcs_port.h"
+#include "fcs_uf.h"
+#include "fcs_vport.h"
+#include "fcs_rport.h"
+#include "fcs_fabric.h"
+#include "fcs_fcpim.h"
+#include "fcs_fcptm.h"
+#include "fcbuild.h"
+#include "fcs.h"
+#include "bfad_drv.h"
+#include <fcb/bfa_fcb.h>
+
+/**
+ * FCS sub-modules
+ */
+struct bfa_fcs_mod_s {
+ void (*modinit) (struct bfa_fcs_s *fcs);
+ void (*modexit) (struct bfa_fcs_s *fcs);
+};
+
+#define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit }
+
+static struct bfa_fcs_mod_s fcs_modules[] = {
+ BFA_FCS_MODULE(bfa_fcs_pport),
+ BFA_FCS_MODULE(bfa_fcs_uf),
+ BFA_FCS_MODULE(bfa_fcs_fabric),
+ BFA_FCS_MODULE(bfa_fcs_vport),
+ BFA_FCS_MODULE(bfa_fcs_rport),
+ BFA_FCS_MODULE(bfa_fcs_fcpim),
+};
+
+/**
+ * fcs_api BFA FCS API
+ */
+
+static void
+bfa_fcs_exit_comp(void *fcs_cbarg)
+{
+ struct bfa_fcs_s *fcs = fcs_cbarg;
+ struct bfad_s *bfad = fcs->bfad;
+
+ complete(&bfad->comp);
+}
+
+
+
+/**
+ * fcs_api BFA FCS API
+ */
+
+/**
+ * FCS instance initialization.
+ *
+ * param[in] fcs FCS instance
+ * param[in] bfa BFA instance
+ * param[in] bfad BFA driver instance
+ *
+ * return None
+ */
+void
+bfa_fcs_init(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
+ bfa_boolean_t min_cfg)
+{
+ int i;
+ struct bfa_fcs_mod_s *mod;
+
+ fcs->bfa = bfa;
+ fcs->bfad = bfad;
+ fcs->min_cfg = min_cfg;
+
+ bfa_attach_fcs(bfa);
+ fcbuild_init();
+
+ for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) {
+ mod = &fcs_modules[i];
+ mod->modinit(fcs);
+ }
+}
+
+/**
+ * Start FCS operations.
+ */
+void
+bfa_fcs_start(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_fabric_modstart(fcs);
+}
+
+/**
+ * FCS driver details initialization.
+ *
+ * param[in] fcs FCS instance
+ * param[in] driver_info Driver Details
+ *
+ * return None
+ */
+void
+bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
+ struct bfa_fcs_driver_info_s *driver_info)
+{
+
+ fcs->driver_info = *driver_info;
+
+ bfa_fcs_fabric_psymb_init(&fcs->fabric);
+}
+
+/**
+ * FCS instance cleanup and exit.
+ *
+ * param[in] fcs FCS instance
+ * return None
+ */
+void
+bfa_fcs_exit(struct bfa_fcs_s *fcs)
+{
+ struct bfa_fcs_mod_s *mod;
+ int nmods, i;
+
+ bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs);
+
+ nmods = sizeof(fcs_modules) / sizeof(fcs_modules[0]);
+
+ for (i = 0; i < nmods; i++) {
+ bfa_wc_up(&fcs->wc);
+
+ mod = &fcs_modules[i];
+ mod->modexit(fcs);
+ }
+
+ bfa_wc_wait(&fcs->wc);
+}
+
+
+void
+bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod)
+{
+ fcs->trcmod = trcmod;
+}
+
+
+void
+bfa_fcs_log_init(struct bfa_fcs_s *fcs, struct bfa_log_mod_s *logmod)
+{
+ fcs->logm = logmod;
+}
+
+
+void
+bfa_fcs_aen_init(struct bfa_fcs_s *fcs, struct bfa_aen_s *aen)
+{
+ fcs->aen = aen;
+}
+
+void
+bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs)
+{
+ bfa_wc_down(&fcs->wc);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcs_lport.c b/drivers/scsi/bfa/bfa_fcs_lport.c
new file mode 100644
index 000000000000..c7ab257f10a7
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcs_lport.c
@@ -0,0 +1,939 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcs_port.c BFA FCS port
+ */
+
+#include <fcs/bfa_fcs.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_rport.h>
+#include <fcb/bfa_fcb_port.h>
+#include <bfa_svc.h>
+#include <log/bfa_log_fcs.h>
+#include "fcs.h"
+#include "fcs_lport.h"
+#include "fcs_vport.h"
+#include "fcs_rport.h"
+#include "fcs_fcxp.h"
+#include "fcs_trcmod.h"
+#include "lport_priv.h"
+#include <aen/bfa_aen_lport.h>
+
+BFA_TRC_FILE(FCS, PORT);
+
+/**
+ * Forward declarations
+ */
+
+static void bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port,
+ enum bfa_lport_aen_event event);
+static void bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs, u8 reason_code,
+ u8 reason_code_expl);
+static void bfa_fcs_port_plogi(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs,
+ struct fc_logi_s *plogi);
+static void bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_deleted(struct bfa_fcs_port_s *port);
+static void bfa_fcs_port_echo(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs,
+ struct fc_echo_s *echo, u16 len);
+static void bfa_fcs_port_rnid(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs,
+ struct fc_rnid_cmd_s *rnid, u16 len);
+static void bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port,
+ struct fc_rnid_general_topology_data_s *gen_topo_data);
+
+static struct {
+ void (*init) (struct bfa_fcs_port_s *port);
+ void (*online) (struct bfa_fcs_port_s *port);
+ void (*offline) (struct bfa_fcs_port_s *port);
+} __port_action[] = {
+ {
+ bfa_fcs_port_unknown_init, bfa_fcs_port_unknown_online,
+ bfa_fcs_port_unknown_offline}, {
+ bfa_fcs_port_fab_init, bfa_fcs_port_fab_online,
+ bfa_fcs_port_fab_offline}, {
+ bfa_fcs_port_loop_init, bfa_fcs_port_loop_online,
+ bfa_fcs_port_loop_offline}, {
+bfa_fcs_port_n2n_init, bfa_fcs_port_n2n_online,
+ bfa_fcs_port_n2n_offline},};
+
+/**
+ * fcs_port_sm FCS logical port state machine
+ */
+
+enum bfa_fcs_port_event {
+ BFA_FCS_PORT_SM_CREATE = 1,
+ BFA_FCS_PORT_SM_ONLINE = 2,
+ BFA_FCS_PORT_SM_OFFLINE = 3,
+ BFA_FCS_PORT_SM_DELETE = 4,
+ BFA_FCS_PORT_SM_DELRPORT = 5,
+};
+
+static void bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event);
+static void bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event);
+static void bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event);
+static void bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event);
+static void bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event);
+
+static void
+bfa_fcs_port_sm_uninit(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event)
+{
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_PORT_SM_CREATE:
+ bfa_sm_set_state(port, bfa_fcs_port_sm_init);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_sm_init(struct bfa_fcs_port_s *port, enum bfa_fcs_port_event event)
+{
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_PORT_SM_ONLINE:
+ bfa_sm_set_state(port, bfa_fcs_port_sm_online);
+ bfa_fcs_port_online_actions(port);
+ break;
+
+ case BFA_FCS_PORT_SM_DELETE:
+ bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
+ bfa_fcs_port_deleted(port);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_sm_online(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event)
+{
+ struct bfa_fcs_rport_s *rport;
+ struct list_head *qe, *qen;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_PORT_SM_OFFLINE:
+ bfa_sm_set_state(port, bfa_fcs_port_sm_offline);
+ bfa_fcs_port_offline_actions(port);
+ break;
+
+ case BFA_FCS_PORT_SM_DELETE:
+
+ __port_action[port->fabric->fab_type].offline(port);
+
+ if (port->num_rports == 0) {
+ bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
+ bfa_fcs_port_deleted(port);
+ } else {
+ bfa_sm_set_state(port, bfa_fcs_port_sm_deleting);
+ list_for_each_safe(qe, qen, &port->rport_q) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ bfa_fcs_rport_delete(rport);
+ }
+ }
+ break;
+
+ case BFA_FCS_PORT_SM_DELRPORT:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_sm_offline(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event)
+{
+ struct bfa_fcs_rport_s *rport;
+ struct list_head *qe, *qen;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_PORT_SM_ONLINE:
+ bfa_sm_set_state(port, bfa_fcs_port_sm_online);
+ bfa_fcs_port_online_actions(port);
+ break;
+
+ case BFA_FCS_PORT_SM_DELETE:
+ if (port->num_rports == 0) {
+ bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
+ bfa_fcs_port_deleted(port);
+ } else {
+ bfa_sm_set_state(port, bfa_fcs_port_sm_deleting);
+ list_for_each_safe(qe, qen, &port->rport_q) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ bfa_fcs_rport_delete(rport);
+ }
+ }
+ break;
+
+ case BFA_FCS_PORT_SM_DELRPORT:
+ case BFA_FCS_PORT_SM_OFFLINE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_sm_deleting(struct bfa_fcs_port_s *port,
+ enum bfa_fcs_port_event event)
+{
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_PORT_SM_DELRPORT:
+ if (port->num_rports == 0) {
+ bfa_sm_set_state(port, bfa_fcs_port_sm_uninit);
+ bfa_fcs_port_deleted(port);
+ }
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * fcs_port_pvt
+ */
+
+/**
+ * Send AEN notification
+ */
+static void
+bfa_fcs_port_aen_post(struct bfa_fcs_port_s *port,
+ enum bfa_lport_aen_event event)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = port->fcs->logm;
+ enum bfa_port_role role = port->port_cfg.roles;
+ wwn_t lpwwn = bfa_fcs_port_get_pwwn(port);
+ char lpwwn_ptr[BFA_STRING_32];
+ char *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] =
+ { "Initiator", "Target", "IPFC" };
+
+ wwn2str(lpwwn_ptr, lpwwn);
+
+ bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX);
+
+ switch (event) {
+ case BFA_LPORT_AEN_ONLINE:
+ bfa_log(logmod, BFA_AEN_LPORT_ONLINE, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_OFFLINE:
+ bfa_log(logmod, BFA_AEN_LPORT_OFFLINE, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_NEW:
+ bfa_log(logmod, BFA_AEN_LPORT_NEW, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_DELETE:
+ bfa_log(logmod, BFA_AEN_LPORT_DELETE, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_DISCONNECT:
+ bfa_log(logmod, BFA_AEN_LPORT_DISCONNECT, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ default:
+ break;
+ }
+
+ aen_data.lport.vf_id = port->fabric->vf_id;
+ aen_data.lport.roles = role;
+ aen_data.lport.ppwwn =
+ bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs));
+ aen_data.lport.lpwwn = lpwwn;
+}
+
+/*
+ * Send a LS reject
+ */
+static void
+bfa_fcs_port_send_ls_rjt(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
+ u8 reason_code, u8 reason_code_expl)
+{
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_rport_s *bfa_rport = NULL;
+ int len;
+
+ bfa_trc(port->fcs, rx_fchs->s_id);
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
+ reason_code, reason_code_expl);
+
+ bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
+ BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
+ FC_MAX_PDUSZ, 0);
+}
+
+/**
+ * Process incoming plogi from a remote port.
+ */
+static void
+bfa_fcs_port_plogi(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
+ struct fc_logi_s *plogi)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ bfa_trc(port->fcs, rx_fchs->d_id);
+ bfa_trc(port->fcs, rx_fchs->s_id);
+
+ /*
+ * If min cfg mode is enabled, drop any incoming PLOGIs
+ */
+ if (__fcs_min_cfg(port->fcs)) {
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ return;
+ }
+
+ if (fc_plogi_parse(rx_fchs) != FC_PARSE_OK) {
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ /*
+ * send a LS reject
+ */
+ bfa_fcs_port_send_ls_rjt(port, rx_fchs,
+ FC_LS_RJT_RSN_PROTOCOL_ERROR,
+ FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS);
+ return;
+ }
+
+ /**
+* Direct Attach P2P mode : verify address assigned by the r-port.
+ */
+ if ((!bfa_fcs_fabric_is_switched(port->fabric))
+ &&
+ (memcmp
+ ((void *)&bfa_fcs_port_get_pwwn(port), (void *)&plogi->port_name,
+ sizeof(wwn_t)) < 0)) {
+ if (BFA_FCS_PID_IS_WKA(rx_fchs->d_id)) {
+ /*
+ * Address assigned to us cannot be a WKA
+ */
+ bfa_fcs_port_send_ls_rjt(port, rx_fchs,
+ FC_LS_RJT_RSN_PROTOCOL_ERROR,
+ FC_LS_RJT_EXP_INVALID_NPORT_ID);
+ return;
+ }
+ port->pid = rx_fchs->d_id;
+ }
+
+ /**
+ * First, check if we know the device by pwwn.
+ */
+ rport = bfa_fcs_port_get_rport_by_pwwn(port, plogi->port_name);
+ if (rport) {
+ /**
+ * Direct Attach P2P mode: handle address assigned by the rport.
+ */
+ if ((!bfa_fcs_fabric_is_switched(port->fabric))
+ &&
+ (memcmp
+ ((void *)&bfa_fcs_port_get_pwwn(port),
+ (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) {
+ port->pid = rx_fchs->d_id;
+ rport->pid = rx_fchs->s_id;
+ }
+ bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
+ return;
+ }
+
+ /**
+ * Next, lookup rport by PID.
+ */
+ rport = bfa_fcs_port_get_rport_by_pid(port, rx_fchs->s_id);
+ if (!rport) {
+ /**
+ * Inbound PLOGI from a new device.
+ */
+ bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
+ return;
+ }
+
+ /**
+ * Rport is known only by PID.
+ */
+ if (rport->pwwn) {
+ /**
+ * This is a different device with the same pid. Old device
+ * disappeared. Send implicit LOGO to old device.
+ */
+ bfa_assert(rport->pwwn != plogi->port_name);
+ bfa_fcs_rport_logo_imp(rport);
+
+ /**
+ * Inbound PLOGI from a new device (with old PID).
+ */
+ bfa_fcs_rport_plogi_create(port, rx_fchs, plogi);
+ return;
+ }
+
+ /**
+ * PLOGI crossing each other.
+ */
+ bfa_assert(rport->pwwn == WWN_NULL);
+ bfa_fcs_rport_plogi(rport, rx_fchs, plogi);
+}
+
+/*
+ * Process incoming ECHO.
+ * Since it does not require a login, it is processed here.
+ */
+static void
+bfa_fcs_port_echo(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
+ struct fc_echo_s *echo, u16 rx_len)
+{
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_rport_s *bfa_rport = NULL;
+ int len, pyld_len;
+
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ bfa_trc(port->fcs, rx_fchs->d_id);
+ bfa_trc(port->fcs, rx_len);
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port), rx_fchs->ox_id);
+
+ /*
+ * Copy the payload (if any) from the echo frame
+ */
+ pyld_len = rx_len - sizeof(struct fchs_s);
+ bfa_trc(port->fcs, pyld_len);
+
+ if (pyld_len > len)
+ memcpy(((u8 *) bfa_fcxp_get_reqbuf(fcxp)) +
+ sizeof(struct fc_echo_s), (echo + 1),
+ (pyld_len - sizeof(struct fc_echo_s)));
+
+ bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
+ BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL,
+ FC_MAX_PDUSZ, 0);
+}
+
+/*
+ * Process incoming RNID.
+ * Since it does not require a login, it is processed here.
+ */
+static void
+bfa_fcs_port_rnid(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
+ struct fc_rnid_cmd_s *rnid, u16 rx_len)
+{
+ struct fc_rnid_common_id_data_s common_id_data;
+ struct fc_rnid_general_topology_data_s gen_topo_data;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_rport_s *bfa_rport = NULL;
+ u16 len;
+ u32 data_format;
+
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ bfa_trc(port->fcs, rx_fchs->d_id);
+ bfa_trc(port->fcs, rx_len);
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ /*
+ * Check Node Indentification Data Format
+ * We only support General Topology Discovery Format.
+ * For any other requested Data Formats, we return Common Node Id Data
+ * only, as per FC-LS.
+ */
+ bfa_trc(port->fcs, rnid->node_id_data_format);
+ if (rnid->node_id_data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) {
+ data_format = RNID_NODEID_DATA_FORMAT_DISCOVERY;
+ /*
+ * Get General topology data for this port
+ */
+ bfa_fs_port_get_gen_topo_data(port, &gen_topo_data);
+ } else {
+ data_format = RNID_NODEID_DATA_FORMAT_COMMON;
+ }
+
+ /*
+ * Copy the Node Id Info
+ */
+ common_id_data.port_name = bfa_fcs_port_get_pwwn(port);
+ common_id_data.node_name = bfa_fcs_port_get_nwwn(port);
+
+ len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
+ data_format, &common_id_data, &gen_topo_data);
+
+ bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
+ BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
+ FC_MAX_PDUSZ, 0);
+
+ return;
+}
+
+/*
+ * Fill out General Topolpgy Discovery Data for RNID ELS.
+ */
+static void
+bfa_fs_port_get_gen_topo_data(struct bfa_fcs_port_s *port,
+ struct fc_rnid_general_topology_data_s *gen_topo_data)
+{
+
+ bfa_os_memset(gen_topo_data, 0,
+ sizeof(struct fc_rnid_general_topology_data_s));
+
+ gen_topo_data->asso_type = bfa_os_htonl(RNID_ASSOCIATED_TYPE_HOST);
+ gen_topo_data->phy_port_num = 0; /* @todo */
+ gen_topo_data->num_attached_nodes = bfa_os_htonl(1);
+}
+
+static void
+bfa_fcs_port_online_actions(struct bfa_fcs_port_s *port)
+{
+ bfa_trc(port->fcs, port->fabric->oper_type);
+
+ __port_action[port->fabric->fab_type].init(port);
+ __port_action[port->fabric->fab_type].online(port);
+
+ bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_ONLINE);
+ bfa_fcb_port_online(port->fcs->bfad, port->port_cfg.roles,
+ port->fabric->vf_drv, (port->vport == NULL) ?
+ NULL : port->vport->vport_drv);
+}
+
+static void
+bfa_fcs_port_offline_actions(struct bfa_fcs_port_s *port)
+{
+ struct list_head *qe, *qen;
+ struct bfa_fcs_rport_s *rport;
+
+ bfa_trc(port->fcs, port->fabric->oper_type);
+
+ __port_action[port->fabric->fab_type].offline(port);
+
+ if (bfa_fcs_fabric_is_online(port->fabric) == BFA_TRUE)
+ bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DISCONNECT);
+ 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);
+
+ list_for_each_safe(qe, qen, &port->rport_q) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ bfa_fcs_rport_offline(rport);
+ }
+}
+
+static void
+bfa_fcs_port_unknown_init(struct bfa_fcs_port_s *port)
+{
+ bfa_assert(0);
+}
+
+static void
+bfa_fcs_port_unknown_online(struct bfa_fcs_port_s *port)
+{
+ bfa_assert(0);
+}
+
+static void
+bfa_fcs_port_unknown_offline(struct bfa_fcs_port_s *port)
+{
+ bfa_assert(0);
+}
+
+static void
+bfa_fcs_port_deleted(struct bfa_fcs_port_s *port)
+{
+ bfa_fcs_port_aen_post(port, BFA_LPORT_AEN_DELETE);
+
+ /*
+ * Base port will be deleted by the OS driver
+ */
+ if (port->vport) {
+ bfa_fcb_port_delete(port->fcs->bfad, port->port_cfg.roles,
+ port->fabric->vf_drv,
+ port->vport ? port->vport->vport_drv : NULL);
+ bfa_fcs_vport_delete_comp(port->vport);
+ } else {
+ bfa_fcs_fabric_port_delete_comp(port->fabric);
+ }
+}
+
+
+
+/**
+ * fcs_lport_api BFA FCS port API
+ */
+/**
+ * Module initialization
+ */
+void
+bfa_fcs_port_modinit(struct bfa_fcs_s *fcs)
+{
+
+}
+
+/**
+ * Module cleanup
+ */
+void
+bfa_fcs_port_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
+
+/**
+ * Unsolicited frame receive handling.
+ */
+void
+bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs,
+ u16 len)
+{
+ u32 pid = fchs->s_id;
+ struct bfa_fcs_rport_s *rport = NULL;
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+
+ bfa_stats(lport, uf_recvs);
+
+ if (!bfa_fcs_port_is_online(lport)) {
+ bfa_stats(lport, uf_recv_drops);
+ return;
+ }
+
+ /**
+ * First, handle ELSs that donot require a login.
+ */
+ /*
+ * Handle PLOGI first
+ */
+ if ((fchs->type == FC_TYPE_ELS) &&
+ (els_cmd->els_code == FC_ELS_PLOGI)) {
+ bfa_fcs_port_plogi(lport, fchs, (struct fc_logi_s *) els_cmd);
+ return;
+ }
+
+ /*
+ * Handle ECHO separately.
+ */
+ if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) {
+ bfa_fcs_port_echo(lport, fchs,
+ (struct fc_echo_s *) els_cmd, len);
+ return;
+ }
+
+ /*
+ * Handle RNID separately.
+ */
+ if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) {
+ bfa_fcs_port_rnid(lport, fchs,
+ (struct fc_rnid_cmd_s *) els_cmd, len);
+ return;
+ }
+
+ /**
+ * look for a matching remote port ID
+ */
+ rport = bfa_fcs_port_get_rport_by_pid(lport, pid);
+ if (rport) {
+ bfa_trc(rport->fcs, fchs->s_id);
+ bfa_trc(rport->fcs, fchs->d_id);
+ bfa_trc(rport->fcs, fchs->type);
+
+ bfa_fcs_rport_uf_recv(rport, fchs, len);
+ return;
+ }
+
+ /**
+ * Only handles ELS frames for now.
+ */
+ if (fchs->type != FC_TYPE_ELS) {
+ bfa_trc(lport->fcs, fchs->type);
+ bfa_assert(0);
+ return;
+ }
+
+ bfa_trc(lport->fcs, els_cmd->els_code);
+ if (els_cmd->els_code == FC_ELS_RSCN) {
+ bfa_fcs_port_scn_process_rscn(lport, fchs, len);
+ return;
+ }
+
+ if (els_cmd->els_code == FC_ELS_LOGO) {
+ /**
+ * @todo Handle LOGO frames received.
+ */
+ bfa_trc(lport->fcs, els_cmd->els_code);
+ return;
+ }
+
+ if (els_cmd->els_code == FC_ELS_PRLI) {
+ /**
+ * @todo Handle PRLI frames received.
+ */
+ bfa_trc(lport->fcs, els_cmd->els_code);
+ return;
+ }
+
+ /**
+ * Unhandled ELS frames. Send a LS_RJT.
+ */
+ bfa_fcs_port_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP,
+ FC_LS_RJT_EXP_NO_ADDL_INFO);
+
+}
+
+/**
+ * PID based Lookup for a R-Port in the Port R-Port Queue
+ */
+struct bfa_fcs_rport_s *
+bfa_fcs_port_get_rport_by_pid(struct bfa_fcs_port_s *port, u32 pid)
+{
+ struct bfa_fcs_rport_s *rport;
+ struct list_head *qe;
+
+ list_for_each(qe, &port->rport_q) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ if (rport->pid == pid)
+ return rport;
+ }
+
+ bfa_trc(port->fcs, pid);
+ return NULL;
+}
+
+/**
+ * PWWN based Lookup for a R-Port in the Port R-Port Queue
+ */
+struct bfa_fcs_rport_s *
+bfa_fcs_port_get_rport_by_pwwn(struct bfa_fcs_port_s *port, wwn_t pwwn)
+{
+ struct bfa_fcs_rport_s *rport;
+ struct list_head *qe;
+
+ list_for_each(qe, &port->rport_q) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ if (wwn_is_equal(rport->pwwn, pwwn))
+ return rport;
+ }
+
+ bfa_trc(port->fcs, pwwn);
+ return NULL;
+}
+
+/**
+ * NWWN based Lookup for a R-Port in the Port R-Port Queue
+ */
+struct bfa_fcs_rport_s *
+bfa_fcs_port_get_rport_by_nwwn(struct bfa_fcs_port_s *port, wwn_t nwwn)
+{
+ struct bfa_fcs_rport_s *rport;
+ struct list_head *qe;
+
+ list_for_each(qe, &port->rport_q) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ if (wwn_is_equal(rport->nwwn, nwwn))
+ return rport;
+ }
+
+ bfa_trc(port->fcs, nwwn);
+ return NULL;
+}
+
+/**
+ * Called by rport module when new rports are discovered.
+ */
+void
+bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port,
+ struct bfa_fcs_rport_s *rport)
+{
+ list_add_tail(&rport->qe, &port->rport_q);
+ port->num_rports++;
+}
+
+/**
+ * Called by rport module to when rports are deleted.
+ */
+void
+bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port,
+ struct bfa_fcs_rport_s *rport)
+{
+ bfa_assert(bfa_q_is_on_q(&port->rport_q, rport));
+ list_del(&rport->qe);
+ port->num_rports--;
+
+ bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT);
+}
+
+/**
+ * Called by fabric for base port when fabric login is complete.
+ * Called by vport for virtual ports when FDISC is complete.
+ */
+void
+bfa_fcs_port_online(struct bfa_fcs_port_s *port)
+{
+ bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE);
+}
+
+/**
+ * Called by fabric for base port when fabric goes offline.
+ * Called by vport for virtual ports when virtual port becomes offline.
+ */
+void
+bfa_fcs_port_offline(struct bfa_fcs_port_s *port)
+{
+ bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE);
+}
+
+/**
+ * Called by fabric to delete base lport and associated resources.
+ *
+ * Called by vport to delete lport and associated resources. Should call
+ * bfa_fcs_vport_delete_comp() for vports on completion.
+ */
+void
+bfa_fcs_port_delete(struct bfa_fcs_port_s *port)
+{
+ bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE);
+}
+
+/**
+ * Called by fabric in private loop topology to process LIP event.
+ */
+void
+bfa_fcs_port_lip(struct bfa_fcs_port_s *port)
+{
+}
+
+/**
+ * Return TRUE if port is online, else return FALSE
+ */
+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);
+}
+
+/**
+ * Logical port initialization of base or virtual port.
+ * Called by fabric for base port or by vport for virtual ports.
+ */
+void
+bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs,
+ u16 vf_id, struct bfa_port_cfg_s *port_cfg,
+ struct bfa_fcs_vport_s *vport)
+{
+ lport->fcs = fcs;
+ lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id);
+ bfa_os_assign(lport->port_cfg, *port_cfg);
+ lport->vport = vport;
+ lport->lp_tag = (vport) ? bfa_lps_get_tag(vport->lps) :
+ bfa_lps_get_tag(lport->fabric->lps);
+
+ INIT_LIST_HEAD(&lport->rport_q);
+ lport->num_rports = 0;
+
+ lport->bfad_port =
+ bfa_fcb_port_new(fcs->bfad, lport, lport->port_cfg.roles,
+ lport->fabric->vf_drv,
+ vport ? vport->vport_drv : NULL);
+ bfa_fcs_port_aen_post(lport, BFA_LPORT_AEN_NEW);
+
+ bfa_sm_set_state(lport, bfa_fcs_port_sm_uninit);
+ bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE);
+}
+
+
+
+/**
+ * fcs_lport_api
+ */
+
+void
+bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port,
+ struct bfa_port_attr_s *port_attr)
+{
+ if (bfa_sm_cmp_state(port, bfa_fcs_port_sm_online))
+ port_attr->pid = port->pid;
+ else
+ port_attr->pid = 0;
+
+ port_attr->port_cfg = port->port_cfg;
+
+ if (port->fabric) {
+ port_attr->port_type = bfa_fcs_fabric_port_type(port->fabric);
+ port_attr->loopback = bfa_fcs_fabric_is_loopback(port->fabric);
+ port_attr->fabric_name = bfa_fcs_port_get_fabric_name(port);
+ memcpy(port_attr->fabric_ip_addr,
+ bfa_fcs_port_get_fabric_ipaddr(port),
+ BFA_FCS_FABRIC_IPADDR_SZ);
+
+ if (port->vport != NULL)
+ port_attr->port_type = BFA_PPORT_TYPE_VPORT;
+
+ } else {
+ port_attr->port_type = BFA_PPORT_TYPE_UNKNOWN;
+ port_attr->state = BFA_PORT_UNINIT;
+ }
+
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcs_port.c b/drivers/scsi/bfa/bfa_fcs_port.c
new file mode 100644
index 000000000000..9c4b24e62de1
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcs_port.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcs_pport.c BFA FCS PPORT ( physical port)
+ */
+
+#include <fcs/bfa_fcs.h>
+#include <bfa_svc.h>
+#include <fcs/bfa_fcs_fabric.h>
+#include "fcs_trcmod.h"
+#include "fcs.h"
+#include "fcs_fabric.h"
+#include "fcs_port.h"
+
+BFA_TRC_FILE(FCS, PPORT);
+
+static void
+bfa_fcs_pport_event_handler(void *cbarg, bfa_pport_event_t event)
+{
+ struct bfa_fcs_s *fcs = cbarg;
+
+ bfa_trc(fcs, event);
+
+ switch (event) {
+ case BFA_PPORT_LINKUP:
+ bfa_fcs_fabric_link_up(&fcs->fabric);
+ break;
+
+ case BFA_PPORT_LINKDOWN:
+ bfa_fcs_fabric_link_down(&fcs->fabric);
+ break;
+
+ case BFA_PPORT_TRUNK_LINKDOWN:
+ bfa_assert(0);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+void
+bfa_fcs_pport_modinit(struct bfa_fcs_s *fcs)
+{
+ bfa_pport_event_register(fcs->bfa, bfa_fcs_pport_event_handler,
+ fcs);
+}
+
+void
+bfa_fcs_pport_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
diff --git a/drivers/scsi/bfa/bfa_fcs_uf.c b/drivers/scsi/bfa/bfa_fcs_uf.c
new file mode 100644
index 000000000000..ad01db6444b2
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcs_uf.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcs_uf.c BFA FCS UF ( Unsolicited Frames)
+ */
+
+#include <fcs/bfa_fcs.h>
+#include <bfa_svc.h>
+#include <fcs/bfa_fcs_fabric.h>
+#include "fcs.h"
+#include "fcs_trcmod.h"
+#include "fcs_fabric.h"
+#include "fcs_uf.h"
+
+BFA_TRC_FILE(FCS, UF);
+
+/**
+ * BFA callback for unsolicited frame receive handler.
+ *
+ * @param[in] cbarg callback arg for receive handler
+ * @param[in] uf unsolicited frame descriptor
+ *
+ * @return None
+ */
+static void
+bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf)
+{
+ struct bfa_fcs_s *fcs = (struct bfa_fcs_s *) cbarg;
+ struct fchs_s *fchs = bfa_uf_get_frmbuf(uf);
+ u16 len = bfa_uf_get_frmlen(uf);
+ struct fc_vft_s *vft;
+ struct bfa_fcs_fabric_s *fabric;
+
+ /**
+ * check for VFT header
+ */
+ if (fchs->routing == FC_RTG_EXT_HDR &&
+ fchs->cat_info == FC_CAT_VFT_HDR) {
+ bfa_stats(fcs, uf.tagged);
+ vft = bfa_uf_get_frmbuf(uf);
+ if (fcs->port_vfid == vft->vf_id)
+ fabric = &fcs->fabric;
+ else
+ fabric = bfa_fcs_vf_lookup(fcs, (u16) vft->vf_id);
+
+ /**
+ * drop frame if vfid is unknown
+ */
+ if (!fabric) {
+ bfa_assert(0);
+ bfa_stats(fcs, uf.vfid_unknown);
+ bfa_uf_free(uf);
+ return;
+ }
+
+ /**
+ * skip vft header
+ */
+ fchs = (struct fchs_s *) (vft + 1);
+ len -= sizeof(struct fc_vft_s);
+
+ bfa_trc(fcs, vft->vf_id);
+ } else {
+ bfa_stats(fcs, uf.untagged);
+ fabric = &fcs->fabric;
+ }
+
+ bfa_trc(fcs, ((u32 *) fchs)[0]);
+ bfa_trc(fcs, ((u32 *) fchs)[1]);
+ bfa_trc(fcs, ((u32 *) fchs)[2]);
+ bfa_trc(fcs, ((u32 *) fchs)[3]);
+ bfa_trc(fcs, ((u32 *) fchs)[4]);
+ bfa_trc(fcs, ((u32 *) fchs)[5]);
+ bfa_trc(fcs, len);
+
+ bfa_fcs_fabric_uf_recv(fabric, fchs, len);
+ bfa_uf_free(uf);
+}
+
+void
+bfa_fcs_uf_modinit(struct bfa_fcs_s *fcs)
+{
+ bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs);
+}
+
+void
+bfa_fcs_uf_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
diff --git a/drivers/scsi/bfa/bfa_fcxp.c b/drivers/scsi/bfa/bfa_fcxp.c
new file mode 100644
index 000000000000..cf0ad6782686
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcxp.c
@@ -0,0 +1,782 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <bfi/bfi_uf.h>
+#include <cs/bfa_debug.h>
+
+BFA_TRC_FILE(HAL, FCXP);
+BFA_MODULE(fcxp);
+
+/**
+ * forward declarations
+ */
+static void __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete);
+static void hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp,
+ struct bfi_fcxp_send_rsp_s *fcxp_rsp);
+static void hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen,
+ struct bfa_fcxp_s *fcxp, struct fchs_s *fchs);
+static void bfa_fcxp_qresume(void *cbarg);
+static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp,
+ struct bfi_fcxp_send_req_s *send_req);
+
+/**
+ * fcxp_pvt BFA FCXP private functions
+ */
+
+static void
+claim_fcxp_req_rsp_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
+{
+ u8 *dm_kva = NULL;
+ u64 dm_pa;
+ u32 buf_pool_sz;
+
+ dm_kva = bfa_meminfo_dma_virt(mi);
+ dm_pa = bfa_meminfo_dma_phys(mi);
+
+ buf_pool_sz = mod->req_pld_sz * mod->num_fcxps;
+
+ /*
+ * Initialize the fcxp req payload list
+ */
+ mod->req_pld_list_kva = dm_kva;
+ mod->req_pld_list_pa = dm_pa;
+ dm_kva += buf_pool_sz;
+ dm_pa += buf_pool_sz;
+ bfa_os_memset(mod->req_pld_list_kva, 0, buf_pool_sz);
+
+ /*
+ * Initialize the fcxp rsp payload list
+ */
+ buf_pool_sz = mod->rsp_pld_sz * mod->num_fcxps;
+ mod->rsp_pld_list_kva = dm_kva;
+ mod->rsp_pld_list_pa = dm_pa;
+ dm_kva += buf_pool_sz;
+ dm_pa += buf_pool_sz;
+ bfa_os_memset(mod->rsp_pld_list_kva, 0, buf_pool_sz);
+
+ bfa_meminfo_dma_virt(mi) = dm_kva;
+ bfa_meminfo_dma_phys(mi) = dm_pa;
+}
+
+static void
+claim_fcxps_mem(struct bfa_fcxp_mod_s *mod, struct bfa_meminfo_s *mi)
+{
+ u16 i;
+ struct bfa_fcxp_s *fcxp;
+
+ fcxp = (struct bfa_fcxp_s *) bfa_meminfo_kva(mi);
+ bfa_os_memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps);
+
+ INIT_LIST_HEAD(&mod->fcxp_free_q);
+ INIT_LIST_HEAD(&mod->fcxp_active_q);
+
+ mod->fcxp_list = fcxp;
+
+ for (i = 0; i < mod->num_fcxps; i++) {
+ fcxp->fcxp_mod = mod;
+ fcxp->fcxp_tag = i;
+
+ list_add_tail(&fcxp->qe, &mod->fcxp_free_q);
+ bfa_reqq_winit(&fcxp->reqq_wqe, bfa_fcxp_qresume, fcxp);
+ fcxp->reqq_waiting = BFA_FALSE;
+
+ fcxp = fcxp + 1;
+ }
+
+ bfa_meminfo_kva(mi) = (void *)fcxp;
+}
+
+static void
+bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
+ u32 *dm_len)
+{
+ u16 num_fcxp_reqs = cfg->fwcfg.num_fcxp_reqs;
+
+ if (num_fcxp_reqs == 0)
+ return;
+
+ /*
+ * Account for req/rsp payload
+ */
+ *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs;
+ if (cfg->drvcfg.min_cfg)
+ *dm_len += BFA_FCXP_MAX_IBUF_SZ * num_fcxp_reqs;
+ else
+ *dm_len += BFA_FCXP_MAX_LBUF_SZ * num_fcxp_reqs;
+
+ /*
+ * Account for fcxp structs
+ */
+ *ndm_len += sizeof(struct bfa_fcxp_s) * num_fcxp_reqs;
+}
+
+static void
+bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+
+ bfa_os_memset(mod, 0, sizeof(struct bfa_fcxp_mod_s));
+ mod->bfa = bfa;
+ mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs;
+
+ /**
+ * Initialize FCXP request and response payload sizes.
+ */
+ mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ;
+ if (!cfg->drvcfg.min_cfg)
+ mod->rsp_pld_sz = BFA_FCXP_MAX_LBUF_SZ;
+
+ INIT_LIST_HEAD(&mod->wait_q);
+
+ claim_fcxp_req_rsp_mem(mod, meminfo);
+ claim_fcxps_mem(mod, meminfo);
+}
+
+static void
+bfa_fcxp_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcxp_detach(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcxp_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcxp_stop(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_fcxp_iocdisable(struct bfa_s *bfa)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+ struct bfa_fcxp_s *fcxp;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &mod->fcxp_active_q) {
+ fcxp = (struct bfa_fcxp_s *) qe;
+ if (fcxp->caller == NULL) {
+ fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
+ BFA_STATUS_IOC_FAILURE, 0, 0, NULL);
+ bfa_fcxp_free(fcxp);
+ } else {
+ fcxp->rsp_status = BFA_STATUS_IOC_FAILURE;
+ bfa_cb_queue(bfa, &fcxp->hcb_qe,
+ __bfa_fcxp_send_cbfn, fcxp);
+ }
+ }
+}
+
+static struct bfa_fcxp_s *
+bfa_fcxp_get(struct bfa_fcxp_mod_s *fm)
+{
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_q_deq(&fm->fcxp_free_q, &fcxp);
+
+ if (fcxp)
+ list_add_tail(&fcxp->qe, &fm->fcxp_active_q);
+
+ return fcxp;
+}
+
+static void
+bfa_fcxp_put(struct bfa_fcxp_s *fcxp)
+{
+ struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
+ struct bfa_fcxp_wqe_s *wqe;
+
+ bfa_q_deq(&mod->wait_q, &wqe);
+ if (wqe) {
+ bfa_trc(mod->bfa, fcxp->fcxp_tag);
+ wqe->alloc_cbfn(wqe->alloc_cbarg, fcxp);
+ return;
+ }
+
+ bfa_assert(bfa_q_is_on_q(&mod->fcxp_active_q, fcxp));
+ list_del(&fcxp->qe);
+ list_add_tail(&fcxp->qe, &mod->fcxp_free_q);
+}
+
+static void
+bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg,
+ bfa_status_t req_status, u32 rsp_len,
+ u32 resid_len, struct fchs_s *rsp_fchs)
+{
+ /**discarded fcxp completion */
+}
+
+static void
+__bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_fcxp_s *fcxp = cbarg;
+
+ if (complete) {
+ fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
+ fcxp->rsp_status, fcxp->rsp_len,
+ fcxp->residue_len, &fcxp->rsp_fchs);
+ } else {
+ bfa_fcxp_free(fcxp);
+ }
+}
+
+static void
+hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+ struct bfa_fcxp_s *fcxp;
+ u16 fcxp_tag = bfa_os_ntohs(fcxp_rsp->fcxp_tag);
+
+ bfa_trc(bfa, fcxp_tag);
+
+ fcxp_rsp->rsp_len = bfa_os_ntohl(fcxp_rsp->rsp_len);
+
+ /**
+ * @todo f/w should not set residue to non-0 when everything
+ * is received.
+ */
+ if (fcxp_rsp->req_status == BFA_STATUS_OK)
+ fcxp_rsp->residue_len = 0;
+ else
+ fcxp_rsp->residue_len = bfa_os_ntohl(fcxp_rsp->residue_len);
+
+ fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag);
+
+ bfa_assert(fcxp->send_cbfn != NULL);
+
+ hal_fcxp_rx_plog(mod->bfa, fcxp, fcxp_rsp);
+
+ if (fcxp->send_cbfn != NULL) {
+ if (fcxp->caller == NULL) {
+ bfa_trc(mod->bfa, fcxp->fcxp_tag);
+
+ fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg,
+ fcxp_rsp->req_status, fcxp_rsp->rsp_len,
+ fcxp_rsp->residue_len, &fcxp_rsp->fchs);
+ /*
+ * fcxp automatically freed on return from the callback
+ */
+ bfa_fcxp_free(fcxp);
+ } else {
+ bfa_trc(mod->bfa, fcxp->fcxp_tag);
+ fcxp->rsp_status = fcxp_rsp->req_status;
+ fcxp->rsp_len = fcxp_rsp->rsp_len;
+ fcxp->residue_len = fcxp_rsp->residue_len;
+ fcxp->rsp_fchs = fcxp_rsp->fchs;
+
+ bfa_cb_queue(bfa, &fcxp->hcb_qe,
+ __bfa_fcxp_send_cbfn, fcxp);
+ }
+ } else {
+ bfa_trc(bfa, fcxp_tag);
+ }
+}
+
+static void
+hal_fcxp_set_local_sges(struct bfi_sge_s *sge, u32 reqlen, u64 req_pa)
+{
+ union bfi_addr_u sga_zero = { {0} };
+
+ sge->sg_len = reqlen;
+ sge->flags = BFI_SGE_DATA_LAST;
+ bfa_dma_addr_set(sge[0].sga, req_pa);
+ bfa_sge_to_be(sge);
+ sge++;
+
+ sge->sga = sga_zero;
+ sge->sg_len = reqlen;
+ sge->flags = BFI_SGE_PGDLEN;
+ bfa_sge_to_be(sge);
+}
+
+static void
+hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp,
+ struct fchs_s *fchs)
+{
+ /*
+ * TODO: TX ox_id
+ */
+ if (reqlen > 0) {
+ if (fcxp->use_ireqbuf) {
+ u32 pld_w0 =
+ *((u32 *) BFA_FCXP_REQ_PLD(fcxp));
+
+ bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP,
+ BFA_PL_EID_TX,
+ reqlen + sizeof(struct fchs_s), fchs, pld_w0);
+ } else {
+ bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP,
+ BFA_PL_EID_TX, reqlen + sizeof(struct fchs_s),
+ fchs);
+ }
+ } else {
+ bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_TX,
+ reqlen + sizeof(struct fchs_s), fchs);
+ }
+}
+
+static void
+hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp,
+ struct bfi_fcxp_send_rsp_s *fcxp_rsp)
+{
+ if (fcxp_rsp->rsp_len > 0) {
+ if (fcxp->use_irspbuf) {
+ u32 pld_w0 =
+ *((u32 *) BFA_FCXP_RSP_PLD(fcxp));
+
+ bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP,
+ BFA_PL_EID_RX,
+ (u16) fcxp_rsp->rsp_len,
+ &fcxp_rsp->fchs, pld_w0);
+ } else {
+ bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP,
+ BFA_PL_EID_RX,
+ (u16) fcxp_rsp->rsp_len,
+ &fcxp_rsp->fchs);
+ }
+ } else {
+ bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_RX,
+ (u16) fcxp_rsp->rsp_len, &fcxp_rsp->fchs);
+ }
+}
+
+/**
+ * Handler to resume sending fcxp when space in available in cpe queue.
+ */
+static void
+bfa_fcxp_qresume(void *cbarg)
+{
+ struct bfa_fcxp_s *fcxp = cbarg;
+ struct bfa_s *bfa = fcxp->fcxp_mod->bfa;
+ struct bfi_fcxp_send_req_s *send_req;
+
+ fcxp->reqq_waiting = BFA_FALSE;
+ send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP);
+ bfa_fcxp_queue(fcxp, send_req);
+}
+
+/**
+ * Queue fcxp send request to foimrware.
+ */
+static void
+bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req)
+{
+ struct bfa_s *bfa = fcxp->fcxp_mod->bfa;
+ struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info;
+ struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info;
+ struct bfa_rport_s *rport = reqi->bfa_rport;
+
+ bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ,
+ bfa_lpuid(bfa));
+
+ send_req->fcxp_tag = bfa_os_htons(fcxp->fcxp_tag);
+ if (rport) {
+ send_req->rport_fw_hndl = rport->fw_handle;
+ send_req->max_frmsz = bfa_os_htons(rport->rport_info.max_frmsz);
+ if (send_req->max_frmsz == 0)
+ send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ);
+ } else {
+ send_req->rport_fw_hndl = 0;
+ send_req->max_frmsz = bfa_os_htons(FC_MAX_PDUSZ);
+ }
+
+ send_req->vf_id = bfa_os_htons(reqi->vf_id);
+ send_req->lp_tag = reqi->lp_tag;
+ send_req->class = reqi->class;
+ send_req->rsp_timeout = rspi->rsp_timeout;
+ send_req->cts = reqi->cts;
+ send_req->fchs = reqi->fchs;
+
+ send_req->req_len = bfa_os_htonl(reqi->req_tot_len);
+ send_req->rsp_maxlen = bfa_os_htonl(rspi->rsp_maxlen);
+
+ /*
+ * setup req sgles
+ */
+ if (fcxp->use_ireqbuf == 1) {
+ hal_fcxp_set_local_sges(send_req->req_sge, reqi->req_tot_len,
+ BFA_FCXP_REQ_PLD_PA(fcxp));
+ } else {
+ if (fcxp->nreq_sgles > 0) {
+ bfa_assert(fcxp->nreq_sgles == 1);
+ hal_fcxp_set_local_sges(send_req->req_sge,
+ reqi->req_tot_len,
+ fcxp->req_sga_cbfn(fcxp->caller,
+ 0));
+ } else {
+ bfa_assert(reqi->req_tot_len == 0);
+ hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0);
+ }
+ }
+
+ /*
+ * setup rsp sgles
+ */
+ if (fcxp->use_irspbuf == 1) {
+ bfa_assert(rspi->rsp_maxlen <= BFA_FCXP_MAX_LBUF_SZ);
+
+ hal_fcxp_set_local_sges(send_req->rsp_sge, rspi->rsp_maxlen,
+ BFA_FCXP_RSP_PLD_PA(fcxp));
+
+ } else {
+ if (fcxp->nrsp_sgles > 0) {
+ bfa_assert(fcxp->nrsp_sgles == 1);
+ hal_fcxp_set_local_sges(send_req->rsp_sge,
+ rspi->rsp_maxlen,
+ fcxp->rsp_sga_cbfn(fcxp->caller,
+ 0));
+ } else {
+ bfa_assert(rspi->rsp_maxlen == 0);
+ hal_fcxp_set_local_sges(send_req->rsp_sge, 0, 0);
+ }
+ }
+
+ hal_fcxp_tx_plog(bfa, reqi->req_tot_len, fcxp, &reqi->fchs);
+
+ bfa_reqq_produce(bfa, BFA_REQQ_FCXP);
+
+ bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP));
+ bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP));
+}
+
+
+/**
+ * hal_fcxp_api BFA FCXP API
+ */
+
+/**
+ * Allocate an FCXP instance to send a response or to send a request
+ * that has a response. Request/response buffers are allocated by caller.
+ *
+ * @param[in] bfa BFA bfa instance
+ * @param[in] nreq_sgles Number of SG elements required for request
+ * buffer. 0, if fcxp internal buffers are used.
+ * Use bfa_fcxp_get_reqbuf() to get the
+ * internal req buffer.
+ * @param[in] req_sgles SG elements describing request buffer. Will be
+ * copied in by BFA and hence can be freed on
+ * return from this function.
+ * @param[in] get_req_sga function ptr to be called to get a request SG
+ * Address (given the sge index).
+ * @param[in] get_req_sglen function ptr to be called to get a request SG
+ * len (given the sge index).
+ * @param[in] get_rsp_sga function ptr to be called to get a response SG
+ * Address (given the sge index).
+ * @param[in] get_rsp_sglen function ptr to be called to get a response SG
+ * len (given the sge index).
+ *
+ * @return FCXP instance. NULL on failure.
+ */
+struct bfa_fcxp_s *
+bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles,
+ int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn,
+ bfa_fcxp_get_sglen_t req_sglen_cbfn,
+ bfa_fcxp_get_sgaddr_t rsp_sga_cbfn,
+ bfa_fcxp_get_sglen_t rsp_sglen_cbfn)
+{
+ struct bfa_fcxp_s *fcxp = NULL;
+ u32 nreq_sgpg, nrsp_sgpg;
+
+ bfa_assert(bfa != NULL);
+
+ fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa));
+ if (fcxp == NULL)
+ return NULL;
+
+ bfa_trc(bfa, fcxp->fcxp_tag);
+
+ fcxp->caller = caller;
+
+ if (nreq_sgles == 0) {
+ fcxp->use_ireqbuf = 1;
+ } else {
+ bfa_assert(req_sga_cbfn != NULL);
+ bfa_assert(req_sglen_cbfn != NULL);
+
+ fcxp->use_ireqbuf = 0;
+ fcxp->req_sga_cbfn = req_sga_cbfn;
+ fcxp->req_sglen_cbfn = req_sglen_cbfn;
+
+ fcxp->nreq_sgles = nreq_sgles;
+
+ /*
+ * alloc required sgpgs
+ */
+ if (nreq_sgles > BFI_SGE_INLINE) {
+ nreq_sgpg = BFA_SGPG_NPAGE(nreq_sgles);
+
+ if (bfa_sgpg_malloc
+ (bfa, &fcxp->req_sgpg_q, nreq_sgpg)
+ != BFA_STATUS_OK) {
+ /* bfa_sgpg_wait(bfa, &fcxp->req_sgpg_wqe,
+ nreq_sgpg); */
+ /*
+ * TODO
+ */
+ }
+ }
+ }
+
+ if (nrsp_sgles == 0) {
+ fcxp->use_irspbuf = 1;
+ } else {
+ bfa_assert(rsp_sga_cbfn != NULL);
+ bfa_assert(rsp_sglen_cbfn != NULL);
+
+ fcxp->use_irspbuf = 0;
+ fcxp->rsp_sga_cbfn = rsp_sga_cbfn;
+ fcxp->rsp_sglen_cbfn = rsp_sglen_cbfn;
+
+ fcxp->nrsp_sgles = nrsp_sgles;
+ /*
+ * alloc required sgpgs
+ */
+ if (nrsp_sgles > BFI_SGE_INLINE) {
+ nrsp_sgpg = BFA_SGPG_NPAGE(nreq_sgles);
+
+ if (bfa_sgpg_malloc
+ (bfa, &fcxp->rsp_sgpg_q, nrsp_sgpg)
+ != BFA_STATUS_OK) {
+ /* bfa_sgpg_wait(bfa, &fcxp->rsp_sgpg_wqe,
+ nrsp_sgpg); */
+ /*
+ * TODO
+ */
+ }
+ }
+ }
+
+ return fcxp;
+}
+
+/**
+ * Get the internal request buffer pointer
+ *
+ * @param[in] fcxp BFA fcxp pointer
+ *
+ * @return pointer to the internal request buffer
+ */
+void *
+bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp)
+{
+ struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
+ void *reqbuf;
+
+ bfa_assert(fcxp->use_ireqbuf == 1);
+ reqbuf = ((u8 *)mod->req_pld_list_kva) +
+ fcxp->fcxp_tag * mod->req_pld_sz;
+ return reqbuf;
+}
+
+u32
+bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp)
+{
+ struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
+
+ return mod->req_pld_sz;
+}
+
+/**
+ * Get the internal response buffer pointer
+ *
+ * @param[in] fcxp BFA fcxp pointer
+ *
+ * @return pointer to the internal request buffer
+ */
+void *
+bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp)
+{
+ struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
+ void *rspbuf;
+
+ bfa_assert(fcxp->use_irspbuf == 1);
+
+ rspbuf = ((u8 *)mod->rsp_pld_list_kva) +
+ fcxp->fcxp_tag * mod->rsp_pld_sz;
+ return rspbuf;
+}
+
+/**
+ * Free the BFA FCXP
+ *
+ * @param[in] fcxp BFA fcxp pointer
+ *
+ * @return void
+ */
+void
+bfa_fcxp_free(struct bfa_fcxp_s *fcxp)
+{
+ struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod;
+
+ bfa_assert(fcxp != NULL);
+ bfa_trc(mod->bfa, fcxp->fcxp_tag);
+ bfa_fcxp_put(fcxp);
+}
+
+/**
+ * Send a FCXP request
+ *
+ * @param[in] fcxp BFA fcxp pointer
+ * @param[in] rport BFA rport pointer. Could be left NULL for WKA rports
+ * @param[in] vf_id virtual Fabric ID
+ * @param[in] lp_tag lport tag
+ * @param[in] cts use Continous sequence
+ * @param[in] cos fc Class of Service
+ * @param[in] reqlen request length, does not include FCHS length
+ * @param[in] fchs fc Header Pointer. The header content will be copied
+ * in by BFA.
+ *
+ * @param[in] cbfn call back function to be called on receiving
+ * the response
+ * @param[in] cbarg arg for cbfn
+ * @param[in] rsp_timeout
+ * response timeout
+ *
+ * @return bfa_status_t
+ */
+void
+bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport,
+ u16 vf_id, u8 lp_tag, bfa_boolean_t cts, enum fc_cos cos,
+ u32 reqlen, struct fchs_s *fchs, bfa_cb_fcxp_send_t cbfn,
+ void *cbarg, u32 rsp_maxlen, u8 rsp_timeout)
+{
+ struct bfa_s *bfa = fcxp->fcxp_mod->bfa;
+ struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info;
+ struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info;
+ struct bfi_fcxp_send_req_s *send_req;
+
+ bfa_trc(bfa, fcxp->fcxp_tag);
+
+ /**
+ * setup request/response info
+ */
+ reqi->bfa_rport = rport;
+ reqi->vf_id = vf_id;
+ reqi->lp_tag = lp_tag;
+ reqi->class = cos;
+ rspi->rsp_timeout = rsp_timeout;
+ reqi->cts = cts;
+ reqi->fchs = *fchs;
+ reqi->req_tot_len = reqlen;
+ rspi->rsp_maxlen = rsp_maxlen;
+ fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp;
+ fcxp->send_cbarg = cbarg;
+
+ /**
+ * If no room in CPE queue, wait for
+ */
+ send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP);
+ if (!send_req) {
+ bfa_trc(bfa, fcxp->fcxp_tag);
+ fcxp->reqq_waiting = BFA_TRUE;
+ bfa_reqq_wait(bfa, BFA_REQQ_FCXP, &fcxp->reqq_wqe);
+ return;
+ }
+
+ bfa_fcxp_queue(fcxp, send_req);
+}
+
+/**
+ * Abort a BFA FCXP
+ *
+ * @param[in] fcxp BFA fcxp pointer
+ *
+ * @return void
+ */
+bfa_status_t
+bfa_fcxp_abort(struct bfa_fcxp_s *fcxp)
+{
+ bfa_assert(0);
+ return BFA_STATUS_OK;
+}
+
+void
+bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe,
+ bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *alloc_cbarg)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+
+ bfa_assert(list_empty(&mod->fcxp_free_q));
+
+ wqe->alloc_cbfn = alloc_cbfn;
+ wqe->alloc_cbarg = alloc_cbarg;
+ list_add_tail(&wqe->qe, &mod->wait_q);
+}
+
+void
+bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+
+ bfa_assert(bfa_q_is_on_q(&mod->wait_q, wqe));
+ list_del(&wqe->qe);
+}
+
+void
+bfa_fcxp_discard(struct bfa_fcxp_s *fcxp)
+{
+ /**
+ * If waiting for room in request queue, cancel reqq wait
+ * and free fcxp.
+ */
+ if (fcxp->reqq_waiting) {
+ fcxp->reqq_waiting = BFA_FALSE;
+ bfa_reqq_wcancel(&fcxp->reqq_wqe);
+ bfa_fcxp_free(fcxp);
+ return;
+ }
+
+ fcxp->send_cbfn = bfa_fcxp_null_comp;
+}
+
+
+
+/**
+ * hal_fcxp_public BFA FCXP public functions
+ */
+
+void
+bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
+{
+ switch (msg->mhdr.msg_id) {
+ case BFI_FCXP_I2H_SEND_RSP:
+ hal_fcxp_send_comp(bfa, (struct bfi_fcxp_send_rsp_s *) msg);
+ break;
+
+ default:
+ bfa_trc(bfa, msg->mhdr.msg_id);
+ bfa_assert(0);
+ }
+}
+
+u32
+bfa_fcxp_get_maxrsp(struct bfa_s *bfa)
+{
+ struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa);
+
+ return mod->rsp_pld_sz;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_fcxp_priv.h b/drivers/scsi/bfa/bfa_fcxp_priv.h
new file mode 100644
index 000000000000..4cda49397da0
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fcxp_priv.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_FCXP_PRIV_H__
+#define __BFA_FCXP_PRIV_H__
+
+#include <cs/bfa_sm.h>
+#include <protocol/fc.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_fcxp.h>
+
+#define BFA_FCXP_MIN (1)
+#define BFA_FCXP_MAX_IBUF_SZ (2 * 1024 + 256)
+#define BFA_FCXP_MAX_LBUF_SZ (4 * 1024 + 256)
+
+struct bfa_fcxp_mod_s {
+ struct bfa_s *bfa; /* backpointer to BFA */
+ struct bfa_fcxp_s *fcxp_list; /* array of FCXPs */
+ u16 num_fcxps; /* max num FCXP requests */
+ struct list_head fcxp_free_q; /* free FCXPs */
+ struct list_head fcxp_active_q; /* active FCXPs */
+ void *req_pld_list_kva; /* list of FCXP req pld */
+ u64 req_pld_list_pa; /* list of FCXP req pld */
+ void *rsp_pld_list_kva; /* list of FCXP resp pld */
+ u64 rsp_pld_list_pa; /* list of FCXP resp pld */
+ struct list_head wait_q; /* wait queue for free fcxp */
+ u32 req_pld_sz;
+ u32 rsp_pld_sz;
+};
+
+#define BFA_FCXP_MOD(__bfa) (&(__bfa)->modules.fcxp_mod)
+#define BFA_FCXP_FROM_TAG(__mod, __tag) (&(__mod)->fcxp_list[__tag])
+
+typedef void (*fcxp_send_cb_t) (struct bfa_s *ioc, struct bfa_fcxp_s *fcxp,
+ void *cb_arg, bfa_status_t req_status,
+ u32 rsp_len, u32 resid_len,
+ struct fchs_s *rsp_fchs);
+
+/**
+ * Information needed for a FCXP request
+ */
+struct bfa_fcxp_req_info_s {
+ struct bfa_rport_s *bfa_rport; /* Pointer to the bfa rport that was
+ *returned from bfa_rport_create().
+ *This could be left NULL for WKA or for
+ *FCXP interactions before the rport
+ *nexus is established
+ */
+ struct fchs_s fchs; /* request FC header structure */
+ u8 cts; /* continous sequence */
+ u8 class; /* FC class for the request/response */
+ u16 max_frmsz; /* max send frame size */
+ u16 vf_id; /* vsan tag if applicable */
+ u8 lp_tag; /* lport tag */
+ u32 req_tot_len; /* request payload total length */
+};
+
+struct bfa_fcxp_rsp_info_s {
+ struct fchs_s rsp_fchs; /* Response frame's FC header will
+ * be *sent back in this field */
+ u8 rsp_timeout; /* timeout in seconds, 0-no response
+ */
+ u8 rsvd2[3];
+ u32 rsp_maxlen; /* max response length expected */
+};
+
+struct bfa_fcxp_s {
+ struct list_head qe; /* fcxp queue element */
+ bfa_sm_t sm; /* state machine */
+ void *caller; /* driver or fcs */
+ struct bfa_fcxp_mod_s *fcxp_mod;
+ /* back pointer to fcxp mod */
+ u16 fcxp_tag; /* internal tag */
+ struct bfa_fcxp_req_info_s req_info;
+ /* request info */
+ struct bfa_fcxp_rsp_info_s rsp_info;
+ /* response info */
+ u8 use_ireqbuf; /* use internal req buf */
+ u8 use_irspbuf; /* use internal rsp buf */
+ u32 nreq_sgles; /* num request SGLEs */
+ u32 nrsp_sgles; /* num response SGLEs */
+ struct list_head req_sgpg_q; /* SG pages for request buf */
+ struct list_head req_sgpg_wqe; /* wait queue for req SG page */
+ struct list_head rsp_sgpg_q; /* SG pages for response buf */
+ struct list_head rsp_sgpg_wqe; /* wait queue for rsp SG page */
+
+ bfa_fcxp_get_sgaddr_t req_sga_cbfn;
+ /* SG elem addr user function */
+ bfa_fcxp_get_sglen_t req_sglen_cbfn;
+ /* SG elem len user function */
+ bfa_fcxp_get_sgaddr_t rsp_sga_cbfn;
+ /* SG elem addr user function */
+ bfa_fcxp_get_sglen_t rsp_sglen_cbfn;
+ /* SG elem len user function */
+ bfa_cb_fcxp_send_t send_cbfn; /* send completion callback */
+ void *send_cbarg; /* callback arg */
+ struct bfa_sge_s req_sge[BFA_FCXP_MAX_SGES];
+ /* req SG elems */
+ struct bfa_sge_s rsp_sge[BFA_FCXP_MAX_SGES];
+ /* rsp SG elems */
+ u8 rsp_status; /* comp: rsp status */
+ u32 rsp_len; /* comp: actual response len */
+ u32 residue_len; /* comp: residual rsp length */
+ struct fchs_s rsp_fchs; /* comp: response fchs */
+ struct bfa_cb_qe_s hcb_qe; /* comp: callback qelem */
+ struct bfa_reqq_wait_s reqq_wqe;
+ bfa_boolean_t reqq_waiting;
+};
+
+#define BFA_FCXP_REQ_PLD(_fcxp) (bfa_fcxp_get_reqbuf(_fcxp))
+
+#define BFA_FCXP_RSP_FCHS(_fcxp) (&((_fcxp)->rsp_info.fchs))
+#define BFA_FCXP_RSP_PLD(_fcxp) (bfa_fcxp_get_rspbuf(_fcxp))
+
+#define BFA_FCXP_REQ_PLD_PA(_fcxp) \
+ ((_fcxp)->fcxp_mod->req_pld_list_pa + \
+ ((_fcxp)->fcxp_mod->req_pld_sz * (_fcxp)->fcxp_tag))
+
+#define BFA_FCXP_RSP_PLD_PA(_fcxp) \
+ ((_fcxp)->fcxp_mod->rsp_pld_list_pa + \
+ ((_fcxp)->fcxp_mod->rsp_pld_sz * (_fcxp)->fcxp_tag))
+
+void bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+#endif /* __BFA_FCXP_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_fwimg_priv.h b/drivers/scsi/bfa/bfa_fwimg_priv.h
new file mode 100644
index 000000000000..1ec1355924d9
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_fwimg_priv.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_FWIMG_PRIV_H__
+#define __BFA_FWIMG_PRIV_H__
+
+#define BFI_FLASH_CHUNK_SZ 256 /* Flash chunk size */
+#define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32))
+
+extern u32 *bfi_image_ct_get_chunk(u32 off);
+extern u32 bfi_image_ct_size;
+extern u32 *bfi_image_cb_get_chunk(u32 off);
+extern u32 bfi_image_cb_size;
+extern u32 *bfi_image_cb;
+extern u32 *bfi_image_ct;
+
+#endif /* __BFA_FWIMG_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_hw_cb.c b/drivers/scsi/bfa/bfa_hw_cb.c
new file mode 100644
index 000000000000..ede1438619e2
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_hw_cb.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa_priv.h>
+#include <bfi/bfi_cbreg.h>
+
+void
+bfa_hwcb_reginit(struct bfa_s *bfa)
+{
+ struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs;
+ bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
+ int i, q, fn = bfa_ioc_pcifn(&bfa->ioc);
+
+ if (fn == 0) {
+ bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS);
+ bfa_regs->intr_mask = (kva + HOSTFN0_INT_MSK);
+ } else {
+ bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS);
+ bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK);
+ }
+
+ for (i = 0; i < BFI_IOC_MAX_CQS; i++) {
+ /*
+ * CPE registers
+ */
+ q = CPE_Q_NUM(fn, i);
+ bfa_regs->cpe_q_pi[i] = (kva + CPE_Q_PI(q));
+ bfa_regs->cpe_q_ci[i] = (kva + CPE_Q_CI(q));
+ bfa_regs->cpe_q_depth[i] = (kva + CPE_Q_DEPTH(q));
+
+ /*
+ * RME registers
+ */
+ q = CPE_Q_NUM(fn, i);
+ bfa_regs->rme_q_pi[i] = (kva + RME_Q_PI(q));
+ bfa_regs->rme_q_ci[i] = (kva + RME_Q_CI(q));
+ bfa_regs->rme_q_depth[i] = (kva + RME_Q_DEPTH(q));
+ }
+}
+
+void
+bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq)
+{
+}
+
+static void
+bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq)
+{
+ bfa_reg_write(bfa->iocfc.bfa_regs.intr_status,
+ __HFN_INT_RME_Q0 << RME_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), rspq));
+}
+
+void
+bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
+ u32 *num_vecs, u32 *max_vec_bit)
+{
+#define __HFN_NUMINTS 13
+ if (bfa_ioc_pcifn(&bfa->ioc) == 0) {
+ *msix_vecs_bmap = (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 |
+ __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 |
+ __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 |
+ __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 |
+ __HFN_INT_MBOX_LPU0);
+ *max_vec_bit = __HFN_INT_MBOX_LPU0;
+ } else {
+ *msix_vecs_bmap = (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 |
+ __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 |
+ __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 |
+ __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 |
+ __HFN_INT_MBOX_LPU1);
+ *max_vec_bit = __HFN_INT_MBOX_LPU1;
+ }
+
+ *msix_vecs_bmap |= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
+ __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS);
+ *num_vecs = __HFN_NUMINTS;
+}
+
+/**
+ * No special setup required for crossbow -- vector assignments are implicit.
+ */
+void
+bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs)
+{
+ int i;
+
+ bfa_assert((nvecs == 1) || (nvecs == __HFN_NUMINTS));
+
+ bfa->msix.nvecs = nvecs;
+ if (nvecs == 1) {
+ for (i = 0; i < BFA_MSIX_CB_MAX; i++)
+ bfa->msix.handler[i] = bfa_msix_all;
+ return;
+ }
+
+ for (i = BFA_MSIX_CPE_Q0; i <= BFA_MSIX_CPE_Q7; i++)
+ bfa->msix.handler[i] = bfa_msix_reqq;
+
+ for (i = BFA_MSIX_RME_Q0; i <= BFA_MSIX_RME_Q7; i++)
+ bfa->msix.handler[i] = bfa_msix_rspq;
+
+ for (; i < BFA_MSIX_CB_MAX; i++)
+ bfa->msix.handler[i] = bfa_msix_lpu_err;
+}
+
+/**
+ * Crossbow -- dummy, interrupts are masked
+ */
+void
+bfa_hwcb_msix_install(struct bfa_s *bfa)
+{
+}
+
+void
+bfa_hwcb_msix_uninstall(struct bfa_s *bfa)
+{
+}
+
+/**
+ * No special enable/disable -- vector assignments are implicit.
+ */
+void
+bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix)
+{
+ bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_hw_ct.c b/drivers/scsi/bfa/bfa_hw_ct.c
new file mode 100644
index 000000000000..51ae5740e6e9
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_hw_ct.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa_priv.h>
+#include <bfi/bfi_ctreg.h>
+#include <bfa_ioc.h>
+
+BFA_TRC_FILE(HAL, IOCFC_CT);
+
+static u32 __ct_msix_err_vec_reg[] = {
+ HOST_MSIX_ERR_INDEX_FN0,
+ HOST_MSIX_ERR_INDEX_FN1,
+ HOST_MSIX_ERR_INDEX_FN2,
+ HOST_MSIX_ERR_INDEX_FN3,
+};
+
+static void
+bfa_hwct_msix_lpu_err_set(struct bfa_s *bfa, bfa_boolean_t msix, int vec)
+{
+ int fn = bfa_ioc_pcifn(&bfa->ioc);
+ bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
+
+ if (msix)
+ bfa_reg_write(kva + __ct_msix_err_vec_reg[fn], vec);
+ else
+ bfa_reg_write(kva + __ct_msix_err_vec_reg[fn], 0);
+}
+
+/**
+ * Dummy interrupt handler for handling spurious interrupt during chip-reinit.
+ */
+static void
+bfa_hwct_msix_dummy(struct bfa_s *bfa, int vec)
+{
+}
+
+void
+bfa_hwct_reginit(struct bfa_s *bfa)
+{
+ struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs;
+ bfa_os_addr_t kva = bfa_ioc_bar0(&bfa->ioc);
+ int i, q, fn = bfa_ioc_pcifn(&bfa->ioc);
+
+ if (fn == 0) {
+ bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS);
+ bfa_regs->intr_mask = (kva + HOSTFN0_INT_MSK);
+ } else {
+ bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS);
+ bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK);
+ }
+
+ for (i = 0; i < BFI_IOC_MAX_CQS; i++) {
+ /*
+ * CPE registers
+ */
+ q = CPE_Q_NUM(fn, i);
+ bfa_regs->cpe_q_pi[i] = (kva + CPE_PI_PTR_Q(q << 5));
+ bfa_regs->cpe_q_ci[i] = (kva + CPE_CI_PTR_Q(q << 5));
+ bfa_regs->cpe_q_depth[i] = (kva + CPE_DEPTH_Q(q << 5));
+ bfa_regs->cpe_q_ctrl[i] = (kva + CPE_QCTRL_Q(q << 5));
+
+ /*
+ * RME registers
+ */
+ q = CPE_Q_NUM(fn, i);
+ bfa_regs->rme_q_pi[i] = (kva + RME_PI_PTR_Q(q << 5));
+ bfa_regs->rme_q_ci[i] = (kva + RME_CI_PTR_Q(q << 5));
+ bfa_regs->rme_q_depth[i] = (kva + RME_DEPTH_Q(q << 5));
+ bfa_regs->rme_q_ctrl[i] = (kva + RME_QCTRL_Q(q << 5));
+ }
+}
+
+void
+bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq)
+{
+ u32 r32;
+
+ r32 = bfa_reg_read(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]);
+ bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq], r32);
+}
+
+void
+bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap,
+ u32 *num_vecs, u32 *max_vec_bit)
+{
+ *msix_vecs_bmap = (1 << BFA_MSIX_CT_MAX) - 1;
+ *max_vec_bit = (1 << (BFA_MSIX_CT_MAX - 1));
+ *num_vecs = BFA_MSIX_CT_MAX;
+}
+
+/**
+ * Setup MSI-X vector for catapult
+ */
+void
+bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs)
+{
+ bfa_assert((nvecs == 1) || (nvecs == BFA_MSIX_CT_MAX));
+ bfa_trc(bfa, nvecs);
+
+ bfa->msix.nvecs = nvecs;
+ bfa_hwct_msix_uninstall(bfa);
+}
+
+void
+bfa_hwct_msix_install(struct bfa_s *bfa)
+{
+ int i;
+
+ if (bfa->msix.nvecs == 0)
+ return;
+
+ if (bfa->msix.nvecs == 1) {
+ for (i = 0; i < BFA_MSIX_CT_MAX; i++)
+ bfa->msix.handler[i] = bfa_msix_all;
+ return;
+ }
+
+ for (i = BFA_MSIX_CPE_Q0; i <= BFA_MSIX_CPE_Q3; i++)
+ bfa->msix.handler[i] = bfa_msix_reqq;
+
+ for (; i <= BFA_MSIX_RME_Q3; i++)
+ bfa->msix.handler[i] = bfa_msix_rspq;
+
+ bfa_assert(i == BFA_MSIX_LPU_ERR);
+ bfa->msix.handler[BFA_MSIX_LPU_ERR] = bfa_msix_lpu_err;
+}
+
+void
+bfa_hwct_msix_uninstall(struct bfa_s *bfa)
+{
+ int i;
+
+ for (i = 0; i < BFA_MSIX_CT_MAX; i++)
+ bfa->msix.handler[i] = bfa_hwct_msix_dummy;
+}
+
+/**
+ * Enable MSI-X vectors
+ */
+void
+bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix)
+{
+ bfa_trc(bfa, 0);
+ bfa_hwct_msix_lpu_err_set(bfa, msix, BFA_MSIX_LPU_ERR);
+ bfa_ioc_isr_mode_set(&bfa->ioc, msix);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_intr.c b/drivers/scsi/bfa/bfa_intr.c
new file mode 100644
index 000000000000..b36540e4ed76
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_intr.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <bfa.h>
+#include <bfi/bfi_cbreg.h>
+#include <bfa_port_priv.h>
+#include <bfa_intr_priv.h>
+#include <cs/bfa_debug.h>
+
+BFA_TRC_FILE(HAL, INTR);
+
+static void
+bfa_msix_errint(struct bfa_s *bfa, u32 intr)
+{
+ bfa_ioc_error_isr(&bfa->ioc);
+}
+
+static void
+bfa_msix_lpu(struct bfa_s *bfa)
+{
+ bfa_ioc_mbox_isr(&bfa->ioc);
+}
+
+void
+bfa_msix_all(struct bfa_s *bfa, int vec)
+{
+ bfa_intx(bfa);
+}
+
+/**
+ * hal_intr_api
+ */
+bfa_boolean_t
+bfa_intx(struct bfa_s *bfa)
+{
+ u32 intr, qintr;
+ int queue;
+
+ intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
+ if (!intr)
+ return BFA_FALSE;
+
+ /**
+ * RME completion queue interrupt
+ */
+ 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++) {
+ if (intr & (__HFN_INT_RME_Q0 << queue))
+ bfa_msix_rspq(bfa, queue & (BFI_IOC_MAX_CQS - 1));
+ }
+ intr &= ~qintr;
+ if (!intr)
+ return BFA_TRUE;
+
+ /**
+ * CPE completion queue interrupt
+ */
+ qintr = intr & __HFN_INT_CPE_MASK;
+ bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, qintr);
+
+ for (queue = 0; queue < BFI_IOC_MAX_CQS_ASIC; queue++) {
+ if (intr & (__HFN_INT_CPE_Q0 << queue))
+ bfa_msix_reqq(bfa, queue & (BFI_IOC_MAX_CQS - 1));
+ }
+ intr &= ~qintr;
+ if (!intr)
+ return BFA_TRUE;
+
+ bfa_msix_lpu_err(bfa, intr);
+
+ return BFA_TRUE;
+}
+
+void
+bfa_isr_enable(struct bfa_s *bfa)
+{
+ u32 intr_unmask;
+ int pci_func = bfa_ioc_pcifn(&bfa->ioc);
+
+ bfa_trc(bfa, pci_func);
+
+ bfa_msix_install(bfa);
+ intr_unmask = (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 |
+ __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS);
+
+ if (pci_func == 0)
+ intr_unmask |= (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 |
+ __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 |
+ __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 |
+ __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 |
+ __HFN_INT_MBOX_LPU0);
+ else
+ intr_unmask |= (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 |
+ __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 |
+ __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 |
+ __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 |
+ __HFN_INT_MBOX_LPU1);
+
+ bfa_reg_write(bfa->iocfc.bfa_regs.intr_status, intr_unmask);
+ bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, ~intr_unmask);
+ bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0);
+}
+
+void
+bfa_isr_disable(struct bfa_s *bfa)
+{
+ bfa_isr_mode_set(bfa, BFA_FALSE);
+ bfa_reg_write(bfa->iocfc.bfa_regs.intr_mask, -1L);
+ bfa_msix_uninstall(bfa);
+}
+
+void
+bfa_msix_reqq(struct bfa_s *bfa, int qid)
+{
+ struct list_head *waitq, *qe, *qen;
+ struct bfa_reqq_wait_s *wqe;
+
+ qid &= (BFI_IOC_MAX_CQS - 1);
+
+ waitq = bfa_reqq(bfa, qid);
+ list_for_each_safe(qe, qen, waitq) {
+ /**
+ * Callback only as long as there is room in request queue
+ */
+ if (bfa_reqq_full(bfa, qid))
+ break;
+
+ list_del(qe);
+ wqe = (struct bfa_reqq_wait_s *) qe;
+ wqe->qresume(wqe->cbarg);
+ }
+}
+
+void
+bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ bfa_trc(bfa, m->mhdr.msg_class);
+ bfa_trc(bfa, m->mhdr.msg_id);
+ bfa_trc(bfa, m->mhdr.mtag.i2htok);
+ bfa_assert(0);
+ bfa_trc_stop(bfa->trcmod);
+}
+
+void
+bfa_msix_rspq(struct bfa_s *bfa, int rsp_qid)
+{
+ struct bfi_msg_s *m;
+ u32 pi, ci;
+
+ bfa_trc_fp(bfa, rsp_qid);
+
+ rsp_qid &= (BFI_IOC_MAX_CQS - 1);
+
+ bfa->iocfc.hwif.hw_rspq_ack(bfa, rsp_qid);
+
+ ci = bfa_rspq_ci(bfa, rsp_qid);
+ pi = bfa_rspq_pi(bfa, rsp_qid);
+
+ bfa_trc_fp(bfa, ci);
+ bfa_trc_fp(bfa, pi);
+
+ if (bfa->rme_process) {
+ while (ci != pi) {
+ m = bfa_rspq_elem(bfa, rsp_qid, ci);
+ bfa_assert_fp(m->mhdr.msg_class < BFI_MC_MAX);
+
+ bfa_isrs[m->mhdr.msg_class] (bfa, m);
+
+ CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems);
+ }
+ }
+
+ /**
+ * update CI
+ */
+ bfa_rspq_ci(bfa, rsp_qid) = pi;
+ bfa_reg_write(bfa->iocfc.bfa_regs.rme_q_ci[rsp_qid], pi);
+ bfa_os_mmiowb();
+}
+
+void
+bfa_msix_lpu_err(struct bfa_s *bfa, int vec)
+{
+ u32 intr;
+
+ intr = bfa_reg_read(bfa->iocfc.bfa_regs.intr_status);
+
+ if (intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1))
+ bfa_msix_lpu(bfa);
+
+ if (intr & (__HFN_INT_ERR_EMC |
+ __HFN_INT_ERR_LPU0 | __HFN_INT_ERR_LPU1 |
+ __HFN_INT_ERR_PSS))
+ bfa_msix_errint(bfa, intr);
+}
+
+void
+bfa_isr_bind(enum bfi_mclass mc, bfa_isr_func_t isr_func)
+{
+ bfa_isrs[mc] = isr_func;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_intr_priv.h b/drivers/scsi/bfa/bfa_intr_priv.h
new file mode 100644
index 000000000000..5fc301cf4d1b
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_intr_priv.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_INTR_PRIV_H__
+#define __BFA_INTR_PRIV_H__
+
+/**
+ * Message handler
+ */
+typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m);
+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_ci(__bfa, __reqq) \
+ (*(u32 *)((__bfa)->iocfc.req_cq_shadow_ci[__reqq].kva))
+
+#define bfa_reqq_full(__bfa, __reqq) \
+ (((bfa_reqq_pi(__bfa, __reqq) + 1) & \
+ ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1)) == \
+ bfa_reqq_ci(__bfa, __reqq))
+
+#define bfa_reqq_next(__bfa, __reqq) \
+ (bfa_reqq_full(__bfa, __reqq) ? NULL : \
+ ((void *)((struct bfi_msg_s *)((__bfa)->iocfc.req_cq_ba[__reqq].kva) \
+ + bfa_reqq_pi((__bfa), (__reqq)))))
+
+#define bfa_reqq_produce(__bfa, __reqq) do { \
+ (__bfa)->iocfc.req_cq_pi[__reqq]++; \
+ (__bfa)->iocfc.req_cq_pi[__reqq] &= \
+ ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \
+ bfa_reg_write((__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq], \
+ (__bfa)->iocfc.req_cq_pi[__reqq]); \
+ bfa_os_mmiowb(); \
+} while (0)
+
+#define bfa_rspq_pi(__bfa, __rspq) \
+ (*(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva))
+
+#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])
+
+#define CQ_INCR(__index, __size) do { \
+ (__index)++; \
+ (__index) &= ((__size) - 1); \
+} while (0)
+
+/**
+ * Queue element to wait for room in request queue. FIFO order is
+ * maintained when fullfilling requests.
+ */
+struct bfa_reqq_wait_s {
+ struct list_head qe;
+ void (*qresume) (void *cbarg);
+ void *cbarg;
+};
+
+/**
+ * Circular queue usage assignments
+ */
+enum {
+ BFA_REQQ_IOC = 0, /* all low-priority IOC msgs */
+ BFA_REQQ_FCXP = 0, /* all FCXP messages */
+ BFA_REQQ_LPS = 0, /* all lport service msgs */
+ BFA_REQQ_PORT = 0, /* all port messages */
+ BFA_REQQ_FLASH = 0, /* for flash module */
+ BFA_REQQ_DIAG = 0, /* for diag module */
+ BFA_REQQ_RPORT = 0, /* all port messages */
+ BFA_REQQ_SBOOT = 0, /* all san boot messages */
+ BFA_REQQ_QOS_LO = 1, /* all low priority IO */
+ BFA_REQQ_QOS_MD = 2, /* all medium priority IO */
+ BFA_REQQ_QOS_HI = 3, /* all high priority IO */
+};
+
+static inline void
+bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg),
+ void *cbarg)
+{
+ wqe->qresume = qresume;
+ wqe->cbarg = cbarg;
+}
+
+#define bfa_reqq(__bfa, __reqq) (&(__bfa)->reqq_waitq[__reqq])
+
+/**
+ * static inline void
+ * bfa_reqq_wait(struct bfa_s *bfa, int reqq, struct bfa_reqq_wait_s *wqe)
+ */
+#define bfa_reqq_wait(__bfa, __reqq, __wqe) do { \
+ \
+ struct list_head *waitq = bfa_reqq(__bfa, __reqq); \
+ \
+ bfa_assert(((__reqq) < BFI_IOC_MAX_CQS)); \
+ bfa_assert((__wqe)->qresume && (__wqe)->cbarg); \
+ \
+ list_add_tail(&(__wqe)->qe, waitq); \
+} while (0)
+
+#define bfa_reqq_wcancel(__wqe) list_del(&(__wqe)->qe)
+
+#endif /* __BFA_INTR_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c
new file mode 100644
index 000000000000..397d7e9eade5
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_ioc.c
@@ -0,0 +1,2382 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <bfa_ioc.h>
+#include <bfa_fwimg_priv.h>
+#include <bfa_trcmod_priv.h>
+#include <cs/bfa_debug.h>
+#include <bfi/bfi_ioc.h>
+#include <bfi/bfi_ctreg.h>
+#include <aen/bfa_aen_ioc.h>
+#include <aen/bfa_aen.h>
+#include <log/bfa_log_hal.h>
+#include <defs/bfa_defs_pci.h>
+
+BFA_TRC_FILE(HAL, IOC);
+
+/**
+ * IOC local definitions
+ */
+#define BFA_IOC_TOV 2000 /* msecs */
+#define BFA_IOC_HB_TOV 1000 /* msecs */
+#define BFA_IOC_HB_FAIL_MAX 4
+#define BFA_IOC_HWINIT_MAX 2
+#define BFA_IOC_FWIMG_MINSZ (16 * 1024)
+#define BFA_IOC_TOV_RECOVER (BFA_IOC_HB_FAIL_MAX * BFA_IOC_HB_TOV \
+ + BFA_IOC_TOV)
+
+#define bfa_ioc_timer_start(__ioc) \
+ bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \
+ bfa_ioc_timeout, (__ioc), BFA_IOC_TOV)
+#define bfa_ioc_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->ioc_timer)
+
+#define BFA_DBG_FWTRC_ENTS (BFI_IOC_TRC_ENTS)
+#define BFA_DBG_FWTRC_LEN \
+ (BFA_DBG_FWTRC_ENTS * sizeof(struct bfa_trc_s) + \
+ (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_FLASH_CHUNK_NO(off) (off / BFI_FLASH_CHUNK_SZ_WORDS)
+#define BFA_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS)
+#define BFA_FLASH_CHUNK_ADDR(chunkno) (chunkno * BFI_FLASH_CHUNK_SZ_WORDS)
+bfa_boolean_t bfa_auto_recover = BFA_FALSE;
+
+/*
+ * forward declarations
+ */
+static void bfa_ioc_aen_post(struct bfa_ioc_s *bfa,
+ enum bfa_ioc_aen_event event);
+static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc);
+static void bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc);
+static void bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc);
+static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force);
+static void bfa_ioc_timeout(void *ioc);
+static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc);
+static void bfa_ioc_send_disable(struct bfa_ioc_s *ioc);
+static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc);
+static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc);
+static void bfa_ioc_hb_stop(struct bfa_ioc_s *ioc);
+static void bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force);
+static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc);
+static void bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc);
+static void bfa_ioc_recover(struct bfa_ioc_s *ioc);
+static bfa_boolean_t bfa_ioc_firmware_lock(struct bfa_ioc_s *ioc);
+static void bfa_ioc_firmware_unlock(struct bfa_ioc_s *ioc);
+static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc);
+static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc);
+
+/**
+ * bfa_ioc_sm
+ */
+
+/**
+ * IOC state machine events
+ */
+enum ioc_event {
+ IOC_E_ENABLE = 1, /* IOC enable request */
+ IOC_E_DISABLE = 2, /* IOC disable request */
+ IOC_E_TIMEOUT = 3, /* f/w response timeout */
+ IOC_E_FWREADY = 4, /* f/w initialization done */
+ IOC_E_FWRSP_GETATTR = 5, /* IOC get attribute response */
+ IOC_E_FWRSP_ENABLE = 6, /* enable f/w response */
+ IOC_E_FWRSP_DISABLE = 7, /* disable f/w response */
+ IOC_E_HBFAIL = 8, /* heartbeat failure */
+ IOC_E_HWERROR = 9, /* hardware error interrupt */
+ IOC_E_SEMLOCKED = 10, /* h/w semaphore is locked */
+ IOC_E_DETACH = 11, /* driver detach cleanup */
+};
+
+bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, fwcheck, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, mismatch, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, semwait, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hwinit, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, initfail, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, hbfail, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event);
+bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event);
+
+static struct bfa_sm_table_s ioc_sm_table[] = {
+ {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET},
+ {BFA_SM(bfa_ioc_sm_fwcheck), BFA_IOC_FWMISMATCH},
+ {BFA_SM(bfa_ioc_sm_mismatch), BFA_IOC_FWMISMATCH},
+ {BFA_SM(bfa_ioc_sm_semwait), BFA_IOC_SEMWAIT},
+ {BFA_SM(bfa_ioc_sm_hwinit), BFA_IOC_HWINIT},
+ {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_HWINIT},
+ {BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR},
+ {BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL},
+ {BFA_SM(bfa_ioc_sm_initfail), BFA_IOC_INITFAIL},
+ {BFA_SM(bfa_ioc_sm_hbfail), BFA_IOC_HBFAIL},
+ {BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING},
+ {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED},
+};
+
+/**
+ * Reset entry actions -- initialize state machine
+ */
+static void
+bfa_ioc_sm_reset_entry(struct bfa_ioc_s *ioc)
+{
+ ioc->retry_count = 0;
+ ioc->auto_recover = bfa_auto_recover;
+}
+
+/**
+ * Beginning state. IOC is in reset state.
+ */
+static void
+bfa_ioc_sm_reset(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_ENABLE:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_disable_comp(ioc);
+ break;
+
+ case IOC_E_DETACH:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * Semaphore should be acquired for version check.
+ */
+static void
+bfa_ioc_sm_fwcheck_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_hw_sem_get(ioc);
+}
+
+/**
+ * Awaiting h/w semaphore to continue with version check.
+ */
+static void
+bfa_ioc_sm_fwcheck(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_SEMLOCKED:
+ if (bfa_ioc_firmware_lock(ioc)) {
+ ioc->retry_count = 0;
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+ } else {
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_mismatch);
+ }
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_disable_comp(ioc);
+ /*
+ * fall through
+ */
+
+ case IOC_E_DETACH:
+ bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ case IOC_E_FWREADY:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * Notify enable completion callback and generate mismatch AEN.
+ */
+static void
+bfa_ioc_sm_mismatch_entry(struct bfa_ioc_s *ioc)
+{
+ /**
+ * Provide enable completion callback and AEN notification only once.
+ */
+ if (ioc->retry_count == 0) {
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_ioc_aen_post(ioc, BFA_IOC_AEN_FWMISMATCH);
+ }
+ ioc->retry_count++;
+ bfa_ioc_timer_start(ioc);
+}
+
+/**
+ * Awaiting firmware version match.
+ */
+static void
+bfa_ioc_sm_mismatch(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_fwcheck);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_disable_comp(ioc);
+ /*
+ * fall through
+ */
+
+ case IOC_E_DETACH:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ case IOC_E_FWREADY:
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * Request for semaphore.
+ */
+static void
+bfa_ioc_sm_semwait_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_hw_sem_get(ioc);
+}
+
+/**
+ * Awaiting semaphore for h/w initialzation.
+ */
+static void
+bfa_ioc_sm_semwait(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_SEMLOCKED:
+ ioc->retry_count = 0;
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_hw_sem_get_cancel(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_hwinit_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_reset(ioc, BFA_FALSE);
+}
+
+/**
+ * Hardware is being initialized. Interrupts are enabled.
+ * Holding hardware semaphore lock.
+ */
+static void
+bfa_ioc_sm_hwinit(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_FWREADY:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling);
+ break;
+
+ case IOC_E_HWERROR:
+ bfa_ioc_timer_stop(ioc);
+ /*
+ * fall through
+ */
+
+ case IOC_E_TIMEOUT:
+ ioc->retry_count++;
+ if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_reset(ioc, BFA_TRUE);
+ break;
+ }
+
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_enabling_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_send_enable(ioc);
+}
+
+/**
+ * Host IOC function is being enabled, awaiting response from firmware.
+ * Semaphore is acquired.
+ */
+static void
+bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_FWRSP_ENABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr);
+ break;
+
+ case IOC_E_HWERROR:
+ bfa_ioc_timer_stop(ioc);
+ /*
+ * fall through
+ */
+
+ case IOC_E_TIMEOUT:
+ ioc->retry_count++;
+ if (ioc->retry_count < BFA_IOC_HWINIT_MAX) {
+ bfa_reg_write(ioc->ioc_regs.ioc_fwstate,
+ BFI_IOC_UNINIT);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hwinit);
+ break;
+ }
+
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_ioc_hw_sem_release(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ case IOC_E_FWREADY:
+ bfa_ioc_send_enable(ioc);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_getattr_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_send_getattr(ioc);
+}
+
+/**
+ * IOC configuration in progress. Timer is active.
+ */
+static void
+bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_FWRSP_GETATTR:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_op);
+ break;
+
+ case IOC_E_HWERROR:
+ bfa_ioc_timer_stop(ioc);
+ /*
+ * fall through
+ */
+
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_initfail);
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc)
+{
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK);
+ bfa_ioc_hb_monitor(ioc);
+ bfa_ioc_aen_post(ioc, BFA_IOC_AEN_ENABLE);
+}
+
+static void
+bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_ENABLE:
+ break;
+
+ case IOC_E_DISABLE:
+ bfa_ioc_hb_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling);
+ break;
+
+ case IOC_E_HWERROR:
+ case IOC_E_FWREADY:
+ /**
+ * Hard error or IOC recovery by other function.
+ * Treat it same as heartbeat failure.
+ */
+ bfa_ioc_hb_stop(ioc);
+ /*
+ * !!! fall through !!!
+ */
+
+ case IOC_E_HBFAIL:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_hbfail);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_aen_post(ioc, BFA_IOC_AEN_DISABLE);
+ bfa_ioc_timer_start(ioc);
+ bfa_ioc_send_disable(ioc);
+}
+
+/**
+ * IOC is being disabled
+ */
+static void
+bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_HWERROR:
+ case IOC_E_FWRSP_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ /*
+ * !!! fall through !!!
+ */
+
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+/**
+ * IOC disable completion entry.
+ */
+static void
+bfa_ioc_sm_disabled_entry(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_disable_comp(ioc);
+}
+
+static void
+bfa_ioc_sm_disabled(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_ENABLE:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ break;
+
+ case IOC_E_DISABLE:
+ ioc->cbfn->disable_cbfn(ioc->bfa);
+ break;
+
+ case IOC_E_FWREADY:
+ break;
+
+ case IOC_E_DETACH:
+ bfa_ioc_firmware_unlock(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_initfail_entry(struct bfa_ioc_s *ioc)
+{
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ bfa_ioc_timer_start(ioc);
+}
+
+/**
+ * Hardware initialization failed.
+ */
+static void
+bfa_ioc_sm_initfail(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+ case IOC_E_DISABLE:
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ case IOC_E_DETACH:
+ bfa_ioc_timer_stop(ioc);
+ bfa_ioc_firmware_unlock(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+ break;
+
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+static void
+bfa_ioc_sm_hbfail_entry(struct bfa_ioc_s *ioc)
+{
+ struct list_head *qe;
+ struct bfa_ioc_hbfail_notify_s *notify;
+
+ /**
+ * Mark IOC as failed in hardware and stop firmware.
+ */
+ bfa_ioc_lpu_stop(ioc);
+ bfa_reg_write(ioc->ioc_regs.ioc_fwstate, BFI_IOC_HBFAIL);
+
+ if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) {
+ bfa_reg_write(ioc->ioc_regs.ll_halt, __FW_INIT_HALT_P);
+ /*
+ * Wait for halt to take effect
+ */
+ bfa_reg_read(ioc->ioc_regs.ll_halt);
+ }
+
+ /**
+ * Notify driver and common modules registered for notification.
+ */
+ ioc->cbfn->hbfail_cbfn(ioc->bfa);
+ list_for_each(qe, &ioc->hb_notify_q) {
+ notify = (struct bfa_ioc_hbfail_notify_s *)qe;
+ notify->cbfn(notify->cbarg);
+ }
+
+ /**
+ * Flush any queued up mailbox requests.
+ */
+ bfa_ioc_mbox_hbfail(ioc);
+ bfa_ioc_aen_post(ioc, BFA_IOC_AEN_HBFAIL);
+
+ /**
+ * Trigger auto-recovery after a delay.
+ */
+ if (ioc->auto_recover) {
+ bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer,
+ bfa_ioc_timeout, ioc, BFA_IOC_TOV_RECOVER);
+ }
+}
+
+/**
+ * IOC heartbeat failure.
+ */
+static void
+bfa_ioc_sm_hbfail(struct bfa_ioc_s *ioc, enum ioc_event event)
+{
+ bfa_trc(ioc, event);
+
+ switch (event) {
+
+ case IOC_E_ENABLE:
+ ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE);
+ break;
+
+ case IOC_E_DISABLE:
+ if (ioc->auto_recover)
+ bfa_ioc_timer_stop(ioc);
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled);
+ break;
+
+ case IOC_E_TIMEOUT:
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_semwait);
+ break;
+
+ case IOC_E_FWREADY:
+ /**
+ * Recovery is already initiated by other function.
+ */
+ break;
+
+ default:
+ bfa_sm_fault(ioc, event);
+ }
+}
+
+
+
+/**
+ * bfa_ioc_pvt BFA IOC private functions
+ */
+
+static void
+bfa_ioc_disable_comp(struct bfa_ioc_s *ioc)
+{
+ struct list_head *qe;
+ struct bfa_ioc_hbfail_notify_s *notify;
+
+ ioc->cbfn->disable_cbfn(ioc->bfa);
+
+ /**
+ * Notify common modules registered for notification.
+ */
+ list_for_each(qe, &ioc->hb_notify_q) {
+ notify = (struct bfa_ioc_hbfail_notify_s *)qe;
+ notify->cbfn(notify->cbarg);
+ }
+}
+
+static void
+bfa_ioc_sem_timeout(void *ioc_arg)
+{
+ struct bfa_ioc_s *ioc = (struct bfa_ioc_s *)ioc_arg;
+
+ bfa_ioc_hw_sem_get(ioc);
+}
+
+static void
+bfa_ioc_usage_sem_get(struct bfa_ioc_s *ioc)
+{
+ u32 r32;
+ int cnt = 0;
+#define BFA_SEM_SPINCNT 1000
+
+ do {
+ r32 = bfa_reg_read(ioc->ioc_regs.ioc_usage_sem_reg);
+ cnt++;
+ if (cnt > BFA_SEM_SPINCNT)
+ break;
+ } while (r32 != 0);
+ bfa_assert(cnt < BFA_SEM_SPINCNT);
+}
+
+static void
+bfa_ioc_usage_sem_release(struct bfa_ioc_s *ioc)
+{
+ bfa_reg_write(ioc->ioc_regs.ioc_usage_sem_reg, 1);
+}
+
+static void
+bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc)
+{
+ u32 r32;
+
+ /**
+ * First read to the semaphore register will return 0, subsequent reads
+ * will return 1. Semaphore is released by writing 0 to the register
+ */
+ r32 = bfa_reg_read(ioc->ioc_regs.ioc_sem_reg);
+ if (r32 == 0) {
+ bfa_fsm_send_event(ioc, IOC_E_SEMLOCKED);
+ return;
+ }
+
+ bfa_timer_begin(ioc->timer_mod, &ioc->sem_timer, bfa_ioc_sem_timeout,
+ ioc, BFA_IOC_TOV);
+}
+
+static void
+bfa_ioc_hw_sem_release(struct bfa_ioc_s *ioc)
+{
+ bfa_reg_write(ioc->ioc_regs.ioc_sem_reg, 1);
+}
+
+static void
+bfa_ioc_hw_sem_get_cancel(struct bfa_ioc_s *ioc)
+{
+ bfa_timer_stop(&ioc->sem_timer);
+}
+
+/**
+ * Initialize LPU local memory (aka secondary memory / SRAM)
+ */
+static void
+bfa_ioc_lmem_init(struct bfa_ioc_s *ioc)
+{
+ u32 pss_ctl;
+ int i;
+#define PSS_LMEM_INIT_TIME 10000
+
+ pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl &= ~__PSS_LMEM_RESET;
+ pss_ctl |= __PSS_LMEM_INIT_EN;
+ pss_ctl |= __PSS_I2C_CLK_DIV(3UL); /* i2c workaround 12.5khz clock */
+ bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+
+ /**
+ * wait for memory initialization to be complete
+ */
+ i = 0;
+ do {
+ pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ i++;
+ } while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME));
+
+ /**
+ * If memory initialization is not successful, IOC timeout will catch
+ * such failures.
+ */
+ bfa_assert(pss_ctl & __PSS_LMEM_INIT_DONE);
+ bfa_trc(ioc, pss_ctl);
+
+ pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN);
+ bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+}
+
+static void
+bfa_ioc_lpu_start(struct bfa_ioc_s *ioc)
+{
+ u32 pss_ctl;
+
+ /**
+ * Take processor out of reset.
+ */
+ pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl &= ~__PSS_LPU0_RESET;
+
+ bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+}
+
+static void
+bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc)
+{
+ u32 pss_ctl;
+
+ /**
+ * Put processors in reset.
+ */
+ pss_ctl = bfa_reg_read(ioc->ioc_regs.pss_ctl_reg);
+ pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET);
+
+ bfa_reg_write(ioc->ioc_regs.pss_ctl_reg, pss_ctl);
+}
+
+/**
+ * Get driver and firmware versions.
+ */
+static void
+bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
+{
+ u32 pgnum, pgoff;
+ u32 loff = 0;
+ int i;
+ u32 *fwsig = (u32 *) fwhdr;
+
+ pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+ pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+
+ for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32));
+ i++) {
+ fwsig[i] = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);
+ loff += sizeof(u32);
+ }
+}
+
+static u32 *
+bfa_ioc_fwimg_get_chunk(struct bfa_ioc_s *ioc, u32 off)
+{
+ if (ioc->ctdev)
+ return bfi_image_ct_get_chunk(off);
+ return bfi_image_cb_get_chunk(off);
+}
+
+static u32
+bfa_ioc_fwimg_get_size(struct bfa_ioc_s *ioc)
+{
+return (ioc->ctdev) ? bfi_image_ct_size : bfi_image_cb_size;
+}
+
+/**
+ * Returns TRUE if same.
+ */
+static bfa_boolean_t
+bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr)
+{
+ struct bfi_ioc_image_hdr_s *drv_fwhdr;
+ int i;
+
+ drv_fwhdr =
+ (struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0);
+
+ for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) {
+ if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i]) {
+ bfa_trc(ioc, i);
+ bfa_trc(ioc, fwhdr->md5sum[i]);
+ bfa_trc(ioc, drv_fwhdr->md5sum[i]);
+ return BFA_FALSE;
+ }
+ }
+
+ bfa_trc(ioc, fwhdr->md5sum[0]);
+ return BFA_TRUE;
+}
+
+/**
+ * Return true if current running version is valid. Firmware signature and
+ * execution context (driver/bios) must match.
+ */
+static bfa_boolean_t
+bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc)
+{
+ struct bfi_ioc_image_hdr_s fwhdr, *drv_fwhdr;
+
+ /**
+ * If bios/efi boot (flash based) -- return true
+ */
+ if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+ return BFA_TRUE;
+
+ bfa_ioc_fwver_get(ioc, &fwhdr);
+ drv_fwhdr =
+ (struct bfi_ioc_image_hdr_s *)bfa_ioc_fwimg_get_chunk(ioc, 0);
+
+ if (fwhdr.signature != drv_fwhdr->signature) {
+ bfa_trc(ioc, fwhdr.signature);
+ bfa_trc(ioc, drv_fwhdr->signature);
+ return BFA_FALSE;
+ }
+
+ if (fwhdr.exec != drv_fwhdr->exec) {
+ bfa_trc(ioc, fwhdr.exec);
+ bfa_trc(ioc, drv_fwhdr->exec);
+ return BFA_FALSE;
+ }
+
+ return bfa_ioc_fwver_cmp(ioc, &fwhdr);
+}
+
+/**
+ * Return true if firmware of current driver matches the running firmware.
+ */
+static bfa_boolean_t
+bfa_ioc_firmware_lock(struct bfa_ioc_s *ioc)
+{
+ enum bfi_ioc_state ioc_fwstate;
+ u32 usecnt;
+ struct bfi_ioc_image_hdr_s fwhdr;
+
+ /**
+ * Firmware match check is relevant only for CNA.
+ */
+ if (!ioc->cna)
+ return BFA_TRUE;
+
+ /**
+ * If bios boot (flash based) -- do not increment usage count
+ */
+ if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+ return BFA_TRUE;
+
+ bfa_ioc_usage_sem_get(ioc);
+ usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
+
+ /**
+ * If usage count is 0, always return TRUE.
+ */
+ if (usecnt == 0) {
+ bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, 1);
+ bfa_ioc_usage_sem_release(ioc);
+ bfa_trc(ioc, usecnt);
+ return BFA_TRUE;
+ }
+
+ ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
+ bfa_trc(ioc, ioc_fwstate);
+
+ /**
+ * Use count cannot be non-zero and chip in uninitialized state.
+ */
+ bfa_assert(ioc_fwstate != BFI_IOC_UNINIT);
+
+ /**
+ * Check if another driver with a different firmware is active
+ */
+ bfa_ioc_fwver_get(ioc, &fwhdr);
+ if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) {
+ bfa_ioc_usage_sem_release(ioc);
+ bfa_trc(ioc, usecnt);
+ return BFA_FALSE;
+ }
+
+ /**
+ * Same firmware version. Increment the reference count.
+ */
+ usecnt++;
+ bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
+ bfa_ioc_usage_sem_release(ioc);
+ bfa_trc(ioc, usecnt);
+ return BFA_TRUE;
+}
+
+static void
+bfa_ioc_firmware_unlock(struct bfa_ioc_s *ioc)
+{
+ u32 usecnt;
+
+ /**
+ * Firmware lock is relevant only for CNA.
+ * If bios boot (flash based) -- do not decrement usage count
+ */
+ if (!ioc->cna || (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ))
+ return;
+
+ /**
+ * decrement usage count
+ */
+ bfa_ioc_usage_sem_get(ioc);
+ usecnt = bfa_reg_read(ioc->ioc_regs.ioc_usage_reg);
+ bfa_assert(usecnt > 0);
+
+ usecnt--;
+ bfa_reg_write(ioc->ioc_regs.ioc_usage_reg, usecnt);
+ bfa_trc(ioc, usecnt);
+
+ bfa_ioc_usage_sem_release(ioc);
+}
+
+/**
+ * Conditionally flush any pending message from firmware at start.
+ */
+static void
+bfa_ioc_msgflush(struct bfa_ioc_s *ioc)
+{
+ u32 r32;
+
+ r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd);
+ if (r32)
+ bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1);
+}
+
+
+static void
+bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force)
+{
+ enum bfi_ioc_state ioc_fwstate;
+ bfa_boolean_t fwvalid;
+
+ ioc_fwstate = bfa_reg_read(ioc->ioc_regs.ioc_fwstate);
+
+ if (force)
+ ioc_fwstate = BFI_IOC_UNINIT;
+
+ bfa_trc(ioc, ioc_fwstate);
+
+ /**
+ * check if firmware is valid
+ */
+ fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ?
+ BFA_FALSE : bfa_ioc_fwver_valid(ioc);
+
+ if (!fwvalid) {
+ bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+ return;
+ }
+
+ /**
+ * If hardware initialization is in progress (initialized by other IOC),
+ * just wait for an initialization completion interrupt.
+ */
+ if (ioc_fwstate == BFI_IOC_INITING) {
+ bfa_trc(ioc, ioc_fwstate);
+ ioc->cbfn->reset_cbfn(ioc->bfa);
+ return;
+ }
+
+ /**
+ * If IOC function is disabled and firmware version is same,
+ * just re-enable IOC.
+ */
+ if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) {
+ bfa_trc(ioc, ioc_fwstate);
+
+ /**
+ * When using MSI-X any pending firmware ready event should
+ * be flushed. Otherwise MSI-X interrupts are not delivered.
+ */
+ bfa_ioc_msgflush(ioc);
+ ioc->cbfn->reset_cbfn(ioc->bfa);
+ bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+ return;
+ }
+
+ /**
+ * Initialize the h/w for any other states.
+ */
+ bfa_ioc_boot(ioc, BFI_BOOT_TYPE_NORMAL, ioc->pcidev.device_id);
+}
+
+static void
+bfa_ioc_timeout(void *ioc_arg)
+{
+ struct bfa_ioc_s *ioc = (struct bfa_ioc_s *)ioc_arg;
+
+ bfa_trc(ioc, 0);
+ bfa_fsm_send_event(ioc, IOC_E_TIMEOUT);
+}
+
+void
+bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len)
+{
+ u32 *msgp = (u32 *) ioc_msg;
+ u32 i;
+
+ bfa_trc(ioc, msgp[0]);
+ bfa_trc(ioc, len);
+
+ bfa_assert(len <= BFI_IOC_MSGLEN_MAX);
+
+ /*
+ * first write msg to mailbox registers
+ */
+ for (i = 0; i < len / sizeof(u32); i++)
+ bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32),
+ bfa_os_wtole(msgp[i]));
+
+ for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++)
+ bfa_reg_write(ioc->ioc_regs.hfn_mbox + i * sizeof(u32), 0);
+
+ /*
+ * write 1 to mailbox CMD to trigger LPU event
+ */
+ bfa_reg_write(ioc->ioc_regs.hfn_mbox_cmd, 1);
+ (void)bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+}
+
+static void
+bfa_ioc_send_enable(struct bfa_ioc_s *ioc)
+{
+ struct bfi_ioc_ctrl_req_s enable_req;
+
+ bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ,
+ bfa_ioc_portid(ioc));
+ enable_req.ioc_class = ioc->ioc_mc;
+ bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s));
+}
+
+static void
+bfa_ioc_send_disable(struct bfa_ioc_s *ioc)
+{
+ struct bfi_ioc_ctrl_req_s disable_req;
+
+ bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ,
+ bfa_ioc_portid(ioc));
+ bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req_s));
+}
+
+static void
+bfa_ioc_send_getattr(struct bfa_ioc_s *ioc)
+{
+ struct bfi_ioc_getattr_req_s attr_req;
+
+ bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ,
+ bfa_ioc_portid(ioc));
+ bfa_dma_be_addr_set(attr_req.attr_addr, ioc->attr_dma.pa);
+ bfa_ioc_mbox_send(ioc, &attr_req, sizeof(attr_req));
+}
+
+static void
+bfa_ioc_hb_check(void *cbarg)
+{
+ struct bfa_ioc_s *ioc = cbarg;
+ u32 hb_count;
+
+ hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
+ if (ioc->hb_count == hb_count) {
+ ioc->hb_fail++;
+ } else {
+ ioc->hb_count = hb_count;
+ ioc->hb_fail = 0;
+ }
+
+ if (ioc->hb_fail >= BFA_IOC_HB_FAIL_MAX) {
+ bfa_log(ioc->logm, BFA_LOG_HAL_HEARTBEAT_FAILURE, hb_count);
+ ioc->hb_fail = 0;
+ bfa_ioc_recover(ioc);
+ return;
+ }
+
+ bfa_ioc_mbox_poll(ioc);
+ bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check, ioc,
+ BFA_IOC_HB_TOV);
+}
+
+static void
+bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc)
+{
+ ioc->hb_fail = 0;
+ ioc->hb_count = bfa_reg_read(ioc->ioc_regs.heartbeat);
+ bfa_timer_begin(ioc->timer_mod, &ioc->ioc_timer, bfa_ioc_hb_check, ioc,
+ BFA_IOC_HB_TOV);
+}
+
+static void
+bfa_ioc_hb_stop(struct bfa_ioc_s *ioc)
+{
+ bfa_timer_stop(&ioc->ioc_timer);
+}
+
+/**
+ * Host to LPU mailbox message addresses
+ */
+static struct {
+ u32 hfn_mbox, lpu_mbox, hfn_pgn;
+} iocreg_fnreg[] = {
+ {
+ HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0}, {
+ HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1}, {
+ HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2}, {
+ HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3}
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 0
+ */
+static struct {
+ u32 hfn, lpu;
+} iocreg_mbcmd_p0[] = {
+ {
+ HOSTFN0_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN0_MBOX0_CMD_STAT}, {
+ HOSTFN1_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN1_MBOX0_CMD_STAT}, {
+ HOSTFN2_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN2_MBOX0_CMD_STAT}, {
+ HOSTFN3_LPU0_MBOX0_CMD_STAT, LPU0_HOSTFN3_MBOX0_CMD_STAT}
+};
+
+/**
+ * Host <-> LPU mailbox command/status registers - port 1
+ */
+static struct {
+ u32 hfn, lpu;
+} iocreg_mbcmd_p1[] = {
+ {
+ HOSTFN0_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN0_MBOX0_CMD_STAT}, {
+ HOSTFN1_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN1_MBOX0_CMD_STAT}, {
+ HOSTFN2_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN2_MBOX0_CMD_STAT}, {
+ HOSTFN3_LPU1_MBOX0_CMD_STAT, LPU1_HOSTFN3_MBOX0_CMD_STAT}
+};
+
+/**
+ * Shared IRQ handling in INTX mode
+ */
+static struct {
+ u32 isr, msk;
+} iocreg_shirq_next[] = {
+ {
+ HOSTFN1_INT_STATUS, HOSTFN1_INT_MSK}, {
+ HOSTFN2_INT_STATUS, HOSTFN2_INT_MSK}, {
+ HOSTFN3_INT_STATUS, HOSTFN3_INT_MSK}, {
+HOSTFN0_INT_STATUS, HOSTFN0_INT_MSK},};
+
+static void
+bfa_ioc_reg_init(struct bfa_ioc_s *ioc)
+{
+ bfa_os_addr_t rb;
+ int pcifn = bfa_ioc_pcifn(ioc);
+
+ rb = bfa_ioc_bar0(ioc);
+
+ ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox;
+ ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox;
+ ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn;
+
+ if (ioc->port_id == 0) {
+ ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG;
+ ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG;
+ ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].hfn;
+ ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p0[pcifn].lpu;
+ ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0;
+ } else {
+ ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG);
+ ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG);
+ ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].hfn;
+ ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd_p1[pcifn].lpu;
+ ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1;
+ }
+
+ /**
+ * Shared IRQ handling in INTX mode
+ */
+ ioc->ioc_regs.shirq_isr_next = rb + iocreg_shirq_next[pcifn].isr;
+ ioc->ioc_regs.shirq_msk_next = rb + iocreg_shirq_next[pcifn].msk;
+
+ /*
+ * PSS control registers
+ */
+ ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG);
+ ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_425_CTL_REG);
+ ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_312_CTL_REG);
+
+ /*
+ * IOC semaphore registers and serialization
+ */
+ ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG);
+ ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG);
+ ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT);
+
+ /**
+ * sram memory access
+ */
+ ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START);
+ ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CB;
+ if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT)
+ ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT;
+}
+
+/**
+ * Initiate a full firmware download.
+ */
+static void
+bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type,
+ u32 boot_param)
+{
+ u32 *fwimg;
+ u32 pgnum, pgoff;
+ u32 loff = 0;
+ u32 chunkno = 0;
+ u32 i;
+
+ /**
+ * Initialize LMEM first before code download
+ */
+ bfa_ioc_lmem_init(ioc);
+
+ /**
+ * Flash based firmware boot
+ */
+ bfa_trc(ioc, bfa_ioc_fwimg_get_size(ioc));
+ if (bfa_ioc_fwimg_get_size(ioc) < BFA_IOC_FWIMG_MINSZ)
+ boot_type = BFI_BOOT_TYPE_FLASH;
+ fwimg = bfa_ioc_fwimg_get_chunk(ioc, chunkno);
+ fwimg[BFI_BOOT_TYPE_OFF / sizeof(u32)] = bfa_os_swap32(boot_type);
+ fwimg[BFI_BOOT_PARAM_OFF / sizeof(u32)] =
+ bfa_os_swap32(boot_param);
+
+ pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+ pgoff = bfa_ioc_smem_pgoff(ioc, loff);
+
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+
+ for (i = 0; i < bfa_ioc_fwimg_get_size(ioc); i++) {
+
+ if (BFA_FLASH_CHUNK_NO(i) != chunkno) {
+ chunkno = BFA_FLASH_CHUNK_NO(i);
+ fwimg = bfa_ioc_fwimg_get_chunk(ioc,
+ BFA_FLASH_CHUNK_ADDR(chunkno));
+ }
+
+ /**
+ * write smem
+ */
+ bfa_mem_write(ioc->ioc_regs.smem_page_start, loff,
+ fwimg[BFA_FLASH_OFFSET_IN_CHUNK(i)]);
+
+ loff += sizeof(u32);
+
+ /**
+ * handle page offset wrap around
+ */
+ loff = PSS_SMEM_PGOFF(loff);
+ if (loff == 0) {
+ pgnum++;
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+ }
+ }
+
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
+ bfa_ioc_smem_pgnum(ioc, 0));
+}
+
+static void
+bfa_ioc_reset(struct bfa_ioc_s *ioc, bfa_boolean_t force)
+{
+ bfa_ioc_hwinit(ioc, force);
+}
+
+/**
+ * Update BFA configuration from firmware configuration.
+ */
+static void
+bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc)
+{
+ struct bfi_ioc_attr_s *attr = ioc->attr;
+
+ attr->adapter_prop = bfa_os_ntohl(attr->adapter_prop);
+ attr->maxfrsize = bfa_os_ntohs(attr->maxfrsize);
+
+ bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR);
+}
+
+/**
+ * Attach time initialization of mbox logic.
+ */
+static void
+bfa_ioc_mbox_attach(struct bfa_ioc_s *ioc)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ int mc;
+
+ INIT_LIST_HEAD(&mod->cmd_q);
+ for (mc = 0; mc < BFI_MC_MAX; mc++) {
+ mod->mbhdlr[mc].cbfn = NULL;
+ mod->mbhdlr[mc].cbarg = ioc->bfa;
+ }
+}
+
+/**
+ * Mbox poll timer -- restarts any pending mailbox requests.
+ */
+static void
+bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ struct bfa_mbox_cmd_s *cmd;
+ u32 stat;
+
+ /**
+ * If no command pending, do nothing
+ */
+ if (list_empty(&mod->cmd_q))
+ return;
+
+ /**
+ * If previous command is not yet fetched by firmware, do nothing
+ */
+ stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+ if (stat)
+ return;
+
+ /**
+ * Enqueue command to firmware.
+ */
+ bfa_q_deq(&mod->cmd_q, &cmd);
+ bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
+}
+
+/**
+ * Cleanup any pending requests.
+ */
+static void
+bfa_ioc_mbox_hbfail(struct bfa_ioc_s *ioc)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ struct bfa_mbox_cmd_s *cmd;
+
+ while (!list_empty(&mod->cmd_q))
+ bfa_q_deq(&mod->cmd_q, &cmd);
+}
+
+/**
+ * Initialize IOC to port mapping.
+ */
+
+#define FNC_PERS_FN_SHIFT(__fn) ((__fn) * 8)
+static void
+bfa_ioc_map_port(struct bfa_ioc_s *ioc)
+{
+ bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
+ u32 r32;
+
+ /**
+ * For crossbow, port id is same as pci function.
+ */
+ if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT) {
+ ioc->port_id = bfa_ioc_pcifn(ioc);
+ return;
+ }
+
+ /**
+ * For catapult, base port id on personality register and IOC type
+ */
+ r32 = bfa_reg_read(rb + FNC_PERS_REG);
+ r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc));
+ ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH;
+
+ bfa_trc(ioc, bfa_ioc_pcifn(ioc));
+ bfa_trc(ioc, ioc->port_id);
+}
+
+
+
+/**
+ * bfa_ioc_public
+ */
+
+/**
+* Set interrupt mode for a function: INTX or MSIX
+ */
+void
+bfa_ioc_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix)
+{
+ bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
+ u32 r32, mode;
+
+ r32 = bfa_reg_read(rb + FNC_PERS_REG);
+ bfa_trc(ioc, r32);
+
+ mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) &
+ __F0_INTX_STATUS;
+
+ /**
+ * If already in desired mode, do not change anything
+ */
+ if (!msix && mode)
+ return;
+
+ if (msix)
+ mode = __F0_INTX_STATUS_MSIX;
+ else
+ mode = __F0_INTX_STATUS_INTA;
+
+ r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+ r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)));
+ bfa_trc(ioc, r32);
+
+ bfa_reg_write(rb + FNC_PERS_REG, r32);
+}
+
+bfa_status_t
+bfa_ioc_pll_init(struct bfa_ioc_s *ioc)
+{
+ bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
+ u32 pll_sclk, pll_fclk, r32;
+
+ if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) {
+ pll_sclk =
+ __APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN |
+ __APP_PLL_312_RSEL200500 | __APP_PLL_312_P0_1(0U) |
+ __APP_PLL_312_JITLMT0_1(3U) |
+ __APP_PLL_312_CNTLMT0_1(1U);
+ pll_fclk =
+ __APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN |
+ __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(0U) |
+ __APP_PLL_425_JITLMT0_1(3U) |
+ __APP_PLL_425_CNTLMT0_1(1U);
+
+ /**
+ * For catapult, choose operational mode FC/FCoE
+ */
+ if (ioc->fcmode) {
+ bfa_reg_write((rb + OP_MODE), 0);
+ bfa_reg_write((rb + ETH_MAC_SER_REG),
+ __APP_EMS_CMLCKSEL | __APP_EMS_REFCKBUFEN2
+ | __APP_EMS_CHANNEL_SEL);
+ } else {
+ ioc->pllinit = BFA_TRUE;
+ bfa_reg_write((rb + OP_MODE), __GLOBAL_FCOE_MODE);
+ bfa_reg_write((rb + ETH_MAC_SER_REG),
+ __APP_EMS_REFCKBUFEN1);
+ }
+ } else {
+ pll_sclk =
+ __APP_PLL_312_ENABLE | __APP_PLL_312_LRESETN |
+ __APP_PLL_312_P0_1(3U) | __APP_PLL_312_JITLMT0_1(3U) |
+ __APP_PLL_312_CNTLMT0_1(3U);
+ pll_fclk =
+ __APP_PLL_425_ENABLE | __APP_PLL_425_LRESETN |
+ __APP_PLL_425_RSEL200500 | __APP_PLL_425_P0_1(3U) |
+ __APP_PLL_425_JITLMT0_1(3U) |
+ __APP_PLL_425_CNTLMT0_1(3U);
+ }
+
+ bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_UNINIT);
+ bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_UNINIT);
+
+ bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN0_INT_MSK), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN1_INT_MSK), 0xffffffffU);
+
+ bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+ __APP_PLL_312_LOGIC_SOFT_RESET);
+ bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+ __APP_PLL_312_BYPASS | __APP_PLL_312_LOGIC_SOFT_RESET);
+ bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+ __APP_PLL_425_LOGIC_SOFT_RESET);
+ bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+ __APP_PLL_425_BYPASS | __APP_PLL_425_LOGIC_SOFT_RESET);
+ bfa_os_udelay(2);
+ bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+ __APP_PLL_312_LOGIC_SOFT_RESET);
+ bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+ __APP_PLL_425_LOGIC_SOFT_RESET);
+
+ bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg,
+ pll_sclk | __APP_PLL_312_LOGIC_SOFT_RESET);
+ bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg,
+ pll_fclk | __APP_PLL_425_LOGIC_SOFT_RESET);
+
+ /**
+ * Wait for PLLs to lock.
+ */
+ bfa_os_udelay(2000);
+ bfa_reg_write((rb + HOSTFN0_INT_STATUS), 0xffffffffU);
+ bfa_reg_write((rb + HOSTFN1_INT_STATUS), 0xffffffffU);
+
+ bfa_reg_write(ioc->ioc_regs.app_pll_slow_ctl_reg, pll_sclk);
+ bfa_reg_write(ioc->ioc_regs.app_pll_fast_ctl_reg, pll_fclk);
+
+ if (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT) {
+ bfa_reg_write((rb + MBIST_CTL_REG), __EDRAM_BISTR_START);
+ bfa_os_udelay(1000);
+ r32 = bfa_reg_read((rb + MBIST_STAT_REG));
+ bfa_trc(ioc, r32);
+ }
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Interface used by diag module to do firmware boot with memory test
+ * as the entry vector.
+ */
+void
+bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param)
+{
+ bfa_os_addr_t rb;
+
+ bfa_ioc_stats(ioc, ioc_boots);
+
+ if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK)
+ return;
+
+ /**
+ * Initialize IOC state of all functions on a chip reset.
+ */
+ rb = ioc->pcidev.pci_bar_kva;
+ if (boot_param == BFI_BOOT_TYPE_MEMTEST) {
+ bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_MEMTEST);
+ bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_MEMTEST);
+ } else {
+ bfa_reg_write((rb + BFA_IOC0_STATE_REG), BFI_IOC_INITING);
+ bfa_reg_write((rb + BFA_IOC1_STATE_REG), BFI_IOC_INITING);
+ }
+
+ bfa_ioc_download_fw(ioc, boot_type, boot_param);
+
+ /**
+ * Enable interrupts just before starting LPU
+ */
+ ioc->cbfn->reset_cbfn(ioc->bfa);
+ bfa_ioc_lpu_start(ioc);
+}
+
+/**
+ * Enable/disable IOC failure auto recovery.
+ */
+void
+bfa_ioc_auto_recover(bfa_boolean_t auto_recover)
+{
+ bfa_auto_recover = BFA_FALSE;
+}
+
+
+bfa_boolean_t
+bfa_ioc_is_operational(struct bfa_ioc_s *ioc)
+{
+ return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op);
+}
+
+void
+bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg)
+{
+ u32 *msgp = mbmsg;
+ u32 r32;
+ int i;
+
+ /**
+ * read the MBOX msg
+ */
+ for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32));
+ i++) {
+ r32 = bfa_reg_read(ioc->ioc_regs.lpu_mbox +
+ i * sizeof(u32));
+ msgp[i] = bfa_os_htonl(r32);
+ }
+
+ /**
+ * turn off mailbox interrupt by clearing mailbox status
+ */
+ bfa_reg_write(ioc->ioc_regs.lpu_mbox_cmd, 1);
+ bfa_reg_read(ioc->ioc_regs.lpu_mbox_cmd);
+}
+
+void
+bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m)
+{
+ union bfi_ioc_i2h_msg_u *msg;
+
+ msg = (union bfi_ioc_i2h_msg_u *)m;
+
+ bfa_ioc_stats(ioc, ioc_isrs);
+
+ switch (msg->mh.msg_id) {
+ case BFI_IOC_I2H_HBEAT:
+ break;
+
+ case BFI_IOC_I2H_READY_EVENT:
+ bfa_fsm_send_event(ioc, IOC_E_FWREADY);
+ break;
+
+ case BFI_IOC_I2H_ENABLE_REPLY:
+ bfa_fsm_send_event(ioc, IOC_E_FWRSP_ENABLE);
+ break;
+
+ case BFI_IOC_I2H_DISABLE_REPLY:
+ bfa_fsm_send_event(ioc, IOC_E_FWRSP_DISABLE);
+ break;
+
+ case BFI_IOC_I2H_GETATTR_REPLY:
+ bfa_ioc_getattr_reply(ioc);
+ break;
+
+ default:
+ bfa_trc(ioc, msg->mh.msg_id);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IOC attach time initialization and setup.
+ *
+ * @param[in] ioc memory for IOC
+ * @param[in] bfa driver instance structure
+ * @param[in] trcmod kernel trace module
+ * @param[in] aen kernel aen event module
+ * @param[in] logm kernel logging module
+ */
+void
+bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn,
+ struct bfa_timer_mod_s *timer_mod, struct bfa_trc_mod_s *trcmod,
+ struct bfa_aen_s *aen, struct bfa_log_mod_s *logm)
+{
+ ioc->bfa = bfa;
+ ioc->cbfn = cbfn;
+ ioc->timer_mod = timer_mod;
+ ioc->trcmod = trcmod;
+ ioc->aen = aen;
+ ioc->logm = logm;
+ ioc->fcmode = BFA_FALSE;
+ ioc->pllinit = BFA_FALSE;
+ ioc->dbg_fwsave_once = BFA_TRUE;
+
+ bfa_ioc_mbox_attach(ioc);
+ INIT_LIST_HEAD(&ioc->hb_notify_q);
+
+ bfa_fsm_set_state(ioc, bfa_ioc_sm_reset);
+}
+
+/**
+ * Driver detach time IOC cleanup.
+ */
+void
+bfa_ioc_detach(struct bfa_ioc_s *ioc)
+{
+ bfa_fsm_send_event(ioc, IOC_E_DETACH);
+}
+
+/**
+ * Setup IOC PCI properties.
+ *
+ * @param[in] pcidev PCI device information for this IOC
+ */
+void
+bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
+ enum bfi_mclass mc)
+{
+ ioc->ioc_mc = mc;
+ ioc->pcidev = *pcidev;
+ ioc->ctdev = (ioc->pcidev.device_id == BFA_PCI_DEVICE_ID_CT);
+ ioc->cna = ioc->ctdev && !ioc->fcmode;
+
+ bfa_ioc_map_port(ioc);
+ bfa_ioc_reg_init(ioc);
+}
+
+/**
+ * Initialize IOC dma memory
+ *
+ * @param[in] dm_kva kernel virtual address of IOC dma memory
+ * @param[in] dm_pa physical address of IOC dma memory
+ */
+void
+bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa)
+{
+ /**
+ * dma memory for firmware attribute
+ */
+ ioc->attr_dma.kva = dm_kva;
+ ioc->attr_dma.pa = dm_pa;
+ ioc->attr = (struct bfi_ioc_attr_s *)dm_kva;
+}
+
+/**
+ * Return size of dma memory required.
+ */
+u32
+bfa_ioc_meminfo(void)
+{
+ return BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ);
+}
+
+void
+bfa_ioc_enable(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_stats(ioc, ioc_enables);
+ ioc->dbg_fwsave_once = BFA_TRUE;
+
+ bfa_fsm_send_event(ioc, IOC_E_ENABLE);
+}
+
+void
+bfa_ioc_disable(struct bfa_ioc_s *ioc)
+{
+ bfa_ioc_stats(ioc, ioc_disables);
+ bfa_fsm_send_event(ioc, IOC_E_DISABLE);
+}
+
+/**
+ * Returns memory required for saving firmware trace in case of crash.
+ * Driver must call this interface to allocate memory required for
+ * automatic saving of firmware trace. Driver should call
+ * bfa_ioc_debug_memclaim() right after bfa_ioc_attach() to setup this
+ * trace memory.
+ */
+int
+bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover)
+{
+return (auto_recover) ? BFA_DBG_FWTRC_LEN : 0;
+}
+
+/**
+ * Initialize memory for saving firmware trace. Driver must initialize
+ * trace memory before call bfa_ioc_enable().
+ */
+void
+bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave)
+{
+ bfa_assert(ioc->auto_recover);
+ ioc->dbg_fwsave = dbg_fwsave;
+ ioc->dbg_fwsave_len = bfa_ioc_debug_trcsz(ioc->auto_recover);
+}
+
+u32
+bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr)
+{
+ return PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, fmaddr);
+}
+
+u32
+bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr)
+{
+ return PSS_SMEM_PGOFF(fmaddr);
+}
+
+/**
+ * Register mailbox message handler functions
+ *
+ * @param[in] ioc IOC instance
+ * @param[in] mcfuncs message class handler functions
+ */
+void
+bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ int mc;
+
+ for (mc = 0; mc < BFI_MC_MAX; mc++)
+ mod->mbhdlr[mc].cbfn = mcfuncs[mc];
+}
+
+/**
+ * Register mailbox message handler function, to be called by common modules
+ */
+void
+bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
+ bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+
+ mod->mbhdlr[mc].cbfn = cbfn;
+ mod->mbhdlr[mc].cbarg = cbarg;
+}
+
+/**
+ * Queue a mailbox command request to firmware. Waits if mailbox is busy.
+ * Responsibility of caller to serialize
+ *
+ * @param[in] ioc IOC instance
+ * @param[i] cmd Mailbox command
+ */
+void
+bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ u32 stat;
+
+ /**
+ * If a previous command is pending, queue new command
+ */
+ if (!list_empty(&mod->cmd_q)) {
+ list_add_tail(&cmd->qe, &mod->cmd_q);
+ return;
+ }
+
+ /**
+ * If mailbox is busy, queue command for poll timer
+ */
+ stat = bfa_reg_read(ioc->ioc_regs.hfn_mbox_cmd);
+ if (stat) {
+ list_add_tail(&cmd->qe, &mod->cmd_q);
+ return;
+ }
+
+ /**
+ * mailbox is free -- queue command to firmware
+ */
+ bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg));
+}
+
+/**
+ * Handle mailbox interrupts
+ */
+void
+bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc)
+{
+ struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod;
+ struct bfi_mbmsg_s m;
+ int mc;
+
+ bfa_ioc_msgget(ioc, &m);
+
+ /**
+ * Treat IOC message class as special.
+ */
+ mc = m.mh.msg_class;
+ if (mc == BFI_MC_IOC) {
+ bfa_ioc_isr(ioc, &m);
+ return;
+ }
+
+ if ((mc > BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL))
+ return;
+
+ mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m);
+}
+
+void
+bfa_ioc_error_isr(struct bfa_ioc_s *ioc)
+{
+ bfa_fsm_send_event(ioc, IOC_E_HWERROR);
+}
+
+#ifndef BFA_BIOS_BUILD
+
+/**
+ * return true if IOC is disabled
+ */
+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 true if IOC firmware is different.
+ */
+bfa_boolean_t
+bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc)
+{
+ 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);
+}
+
+#define bfa_ioc_state_disabled(__sm) \
+ (((__sm) == BFI_IOC_UNINIT) || \
+ ((__sm) == BFI_IOC_INITING) || \
+ ((__sm) == BFI_IOC_HWINIT) || \
+ ((__sm) == BFI_IOC_DISABLED) || \
+ ((__sm) == BFI_IOC_HBFAIL) || \
+ ((__sm) == BFI_IOC_CFG_DISABLED))
+
+/**
+ * Check if adapter is disabled -- both IOCs should be in a disabled
+ * state.
+ */
+bfa_boolean_t
+bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc)
+{
+ u32 ioc_state;
+ bfa_os_addr_t rb = ioc->pcidev.pci_bar_kva;
+
+ if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled))
+ return BFA_FALSE;
+
+ ioc_state = bfa_reg_read(rb + BFA_IOC0_STATE_REG);
+ if (!bfa_ioc_state_disabled(ioc_state))
+ return BFA_FALSE;
+
+ ioc_state = bfa_reg_read(rb + BFA_IOC1_STATE_REG);
+ if (!bfa_ioc_state_disabled(ioc_state))
+ return BFA_FALSE;
+
+ return BFA_TRUE;
+}
+
+/**
+ * Add to IOC heartbeat failure notification queue. To be used by common
+ * modules such as
+ */
+void
+bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
+ struct bfa_ioc_hbfail_notify_s *notify)
+{
+ list_add_tail(&notify->qe, &ioc->hb_notify_q);
+}
+
+#define BFA_MFG_NAME "Brocade"
+void
+bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
+ struct bfa_adapter_attr_s *ad_attr)
+{
+ struct bfi_ioc_attr_s *ioc_attr;
+ char model[BFA_ADAPTER_MODEL_NAME_LEN];
+
+ ioc_attr = ioc->attr;
+ bfa_os_memcpy((void *)&ad_attr->serial_num,
+ (void *)ioc_attr->brcd_serialnum,
+ BFA_ADAPTER_SERIAL_NUM_LEN);
+
+ bfa_os_memcpy(&ad_attr->fw_ver, ioc_attr->fw_version, BFA_VERSION_LEN);
+ bfa_os_memcpy(&ad_attr->optrom_ver, ioc_attr->optrom_version,
+ BFA_VERSION_LEN);
+ bfa_os_memcpy(&ad_attr->manufacturer, BFA_MFG_NAME,
+ BFA_ADAPTER_MFG_NAME_LEN);
+ bfa_os_memcpy(&ad_attr->vpd, &ioc_attr->vpd,
+ sizeof(struct bfa_mfg_vpd_s));
+
+ ad_attr->nports = BFI_ADAPTER_GETP(NPORTS, ioc_attr->adapter_prop);
+ ad_attr->max_speed = BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop);
+
+ /**
+ * model name
+ */
+ if (BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop) == 10) {
+ strcpy(model, "BR-10?0");
+ model[5] = '0' + ad_attr->nports;
+ } else {
+ strcpy(model, "Brocade-??5");
+ model[8] =
+ '0' + BFI_ADAPTER_GETP(SPEED, ioc_attr->adapter_prop);
+ model[9] = '0' + ad_attr->nports;
+ }
+
+ if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop))
+ ad_attr->prototype = 1;
+ else
+ ad_attr->prototype = 0;
+
+ bfa_os_memcpy(&ad_attr->model, model, BFA_ADAPTER_MODEL_NAME_LEN);
+ bfa_os_memcpy(&ad_attr->model_descr, &ad_attr->model,
+ BFA_ADAPTER_MODEL_NAME_LEN);
+
+ ad_attr->pwwn = bfa_ioc_get_pwwn(ioc);
+ ad_attr->mac = bfa_ioc_get_mac(ioc);
+
+ ad_attr->pcie_gen = ioc_attr->pcie_gen;
+ ad_attr->pcie_lanes = ioc_attr->pcie_lanes;
+ ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig;
+ ad_attr->asic_rev = ioc_attr->asic_rev;
+ ad_attr->hw_ver[0] = 'R';
+ ad_attr->hw_ver[1] = 'e';
+ ad_attr->hw_ver[2] = 'v';
+ ad_attr->hw_ver[3] = '-';
+ ad_attr->hw_ver[4] = ioc_attr->asic_rev;
+ ad_attr->hw_ver[5] = '\0';
+
+ ad_attr->cna_capable = ioc->cna;
+}
+
+void
+bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr)
+{
+ bfa_os_memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr_s));
+
+ ioc_attr->state = bfa_sm_to_state(ioc_sm_table, ioc->fsm);
+ ioc_attr->port_id = ioc->port_id;
+
+ if (!ioc->ctdev)
+ ioc_attr->ioc_type = BFA_IOC_TYPE_FC;
+ else if (ioc->ioc_mc == BFI_MC_IOCFC)
+ ioc_attr->ioc_type = BFA_IOC_TYPE_FCoE;
+ else if (ioc->ioc_mc == BFI_MC_LL)
+ ioc_attr->ioc_type = BFA_IOC_TYPE_LL;
+
+ bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr);
+
+ ioc_attr->pci_attr.device_id = ioc->pcidev.device_id;
+ ioc_attr->pci_attr.pcifn = ioc->pcidev.pci_func;
+ ioc_attr->pci_attr.chip_rev[0] = 'R';
+ ioc_attr->pci_attr.chip_rev[1] = 'e';
+ ioc_attr->pci_attr.chip_rev[2] = 'v';
+ ioc_attr->pci_attr.chip_rev[3] = '-';
+ ioc_attr->pci_attr.chip_rev[4] = ioc_attr->adapter_attr.asic_rev;
+ ioc_attr->pci_attr.chip_rev[5] = '\0';
+}
+
+/**
+ * hal_wwn_public
+ */
+wwn_t
+bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc)
+{
+ union {
+ wwn_t wwn;
+ u8 byte[sizeof(wwn_t)];
+ }
+ w;
+
+ w.wwn = ioc->attr->mfg_wwn;
+
+ if (bfa_ioc_portid(ioc) == 1)
+ w.byte[7]++;
+
+ return w.wwn;
+}
+
+wwn_t
+bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc)
+{
+ union {
+ wwn_t wwn;
+ u8 byte[sizeof(wwn_t)];
+ }
+ w;
+
+ w.wwn = ioc->attr->mfg_wwn;
+
+ if (bfa_ioc_portid(ioc) == 1)
+ w.byte[7]++;
+
+ w.byte[0] = 0x20;
+
+ return w.wwn;
+}
+
+wwn_t
+bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst)
+{
+ union {
+ wwn_t wwn;
+ u8 byte[sizeof(wwn_t)];
+ }
+ w , w5;
+
+ bfa_trc(ioc, inst);
+
+ w.wwn = ioc->attr->mfg_wwn;
+ w5.byte[0] = 0x50 | w.byte[2] >> 4;
+ w5.byte[1] = w.byte[2] << 4 | w.byte[3] >> 4;
+ w5.byte[2] = w.byte[3] << 4 | w.byte[4] >> 4;
+ w5.byte[3] = w.byte[4] << 4 | w.byte[5] >> 4;
+ w5.byte[4] = w.byte[5] << 4 | w.byte[6] >> 4;
+ w5.byte[5] = w.byte[6] << 4 | w.byte[7] >> 4;
+ w5.byte[6] = w.byte[7] << 4 | (inst & 0x0f00) >> 8;
+ w5.byte[7] = (inst & 0xff);
+
+ return w5.wwn;
+}
+
+u64
+bfa_ioc_get_adid(struct bfa_ioc_s *ioc)
+{
+ return ioc->attr->mfg_wwn;
+}
+
+mac_t
+bfa_ioc_get_mac(struct bfa_ioc_s *ioc)
+{
+ mac_t mac;
+
+ mac = ioc->attr->mfg_mac;
+ mac.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc);
+
+ return mac;
+}
+
+void
+bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc)
+{
+ ioc->fcmode = BFA_TRUE;
+ ioc->port_id = bfa_ioc_pcifn(ioc);
+}
+
+bfa_boolean_t
+bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc)
+{
+ return ioc->fcmode || (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_CT);
+}
+
+/**
+ * Return true if interrupt should be claimed.
+ */
+bfa_boolean_t
+bfa_ioc_intx_claim(struct bfa_ioc_s *ioc)
+{
+ u32 isr, msk;
+
+ /**
+ * Always claim if not catapult.
+ */
+ if (!ioc->ctdev)
+ return BFA_TRUE;
+
+ /**
+ * FALSE if next device is claiming interrupt.
+ * TRUE if next device is not interrupting or not present.
+ */
+ msk = bfa_reg_read(ioc->ioc_regs.shirq_msk_next);
+ isr = bfa_reg_read(ioc->ioc_regs.shirq_isr_next);
+ return !(isr & ~msk);
+}
+
+/**
+ * Send AEN notification
+ */
+static void
+bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = ioc->logm;
+ s32 inst_num = 0;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ switch (event) {
+ case BFA_IOC_AEN_HBGOOD:
+ bfa_log(logmod, BFA_AEN_IOC_HBGOOD, inst_num);
+ break;
+ case BFA_IOC_AEN_HBFAIL:
+ bfa_log(logmod, BFA_AEN_IOC_HBFAIL, inst_num);
+ break;
+ case BFA_IOC_AEN_ENABLE:
+ bfa_log(logmod, BFA_AEN_IOC_ENABLE, inst_num);
+ break;
+ case BFA_IOC_AEN_DISABLE:
+ bfa_log(logmod, BFA_AEN_IOC_DISABLE, inst_num);
+ break;
+ case BFA_IOC_AEN_FWMISMATCH:
+ bfa_log(logmod, BFA_AEN_IOC_FWMISMATCH, inst_num);
+ break;
+ default:
+ break;
+ }
+
+ memset(&aen_data.ioc.pwwn, 0, sizeof(aen_data.ioc.pwwn));
+ memset(&aen_data.ioc.mac, 0, sizeof(aen_data.ioc.mac));
+ bfa_ioc_get_attr(ioc, &ioc_attr);
+ switch (ioc_attr.ioc_type) {
+ case BFA_IOC_TYPE_FC:
+ aen_data.ioc.pwwn = bfa_ioc_get_pwwn(ioc);
+ break;
+ case BFA_IOC_TYPE_FCoE:
+ aen_data.ioc.pwwn = bfa_ioc_get_pwwn(ioc);
+ aen_data.ioc.mac = bfa_ioc_get_mac(ioc);
+ break;
+ case BFA_IOC_TYPE_LL:
+ aen_data.ioc.mac = bfa_ioc_get_mac(ioc);
+ break;
+ default:
+ bfa_assert(ioc_attr.ioc_type == BFA_IOC_TYPE_FC);
+ break;
+ }
+ aen_data.ioc.ioc_type = ioc_attr.ioc_type;
+}
+
+/**
+ * Retrieve saved firmware trace from a prior IOC failure.
+ */
+bfa_status_t
+bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)
+{
+ int tlen;
+
+ if (ioc->dbg_fwsave_len == 0)
+ return BFA_STATUS_ENOFSAVE;
+
+ tlen = *trclen;
+ if (tlen > ioc->dbg_fwsave_len)
+ tlen = ioc->dbg_fwsave_len;
+
+ bfa_os_memcpy(trcdata, ioc->dbg_fwsave, tlen);
+ *trclen = tlen;
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Retrieve saved firmware trace from a prior IOC failure.
+ */
+bfa_status_t
+bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen)
+{
+ u32 pgnum;
+ u32 loff = BFA_DBG_FWTRC_OFF(bfa_ioc_portid(ioc));
+ int i, tlen;
+ u32 *tbuf = trcdata, r32;
+
+ bfa_trc(ioc, *trclen);
+
+ pgnum = bfa_ioc_smem_pgnum(ioc, loff);
+ loff = bfa_ioc_smem_pgoff(ioc, loff);
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+
+ tlen = *trclen;
+ if (tlen > BFA_DBG_FWTRC_LEN)
+ tlen = BFA_DBG_FWTRC_LEN;
+ tlen /= sizeof(u32);
+
+ bfa_trc(ioc, tlen);
+
+ for (i = 0; i < tlen; i++) {
+ r32 = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff);
+ tbuf[i] = bfa_os_ntohl(r32);
+ loff += sizeof(u32);
+
+ /**
+ * handle page offset wrap around
+ */
+ loff = PSS_SMEM_PGOFF(loff);
+ if (loff == 0) {
+ pgnum++;
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn, pgnum);
+ }
+ }
+ bfa_reg_write(ioc->ioc_regs.host_page_num_fn,
+ bfa_ioc_smem_pgnum(ioc, 0));
+ bfa_trc(ioc, pgnum);
+
+ *trclen = tlen * sizeof(u32);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Save firmware trace if configured.
+ */
+static void
+bfa_ioc_debug_save(struct bfa_ioc_s *ioc)
+{
+ int tlen;
+
+ if (ioc->dbg_fwsave_len) {
+ tlen = ioc->dbg_fwsave_len;
+ bfa_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen);
+ }
+}
+
+/**
+ * Firmware failure detected. Start recovery actions.
+ */
+static void
+bfa_ioc_recover(struct bfa_ioc_s *ioc)
+{
+ if (ioc->dbg_fwsave_once) {
+ ioc->dbg_fwsave_once = BFA_FALSE;
+ bfa_ioc_debug_save(ioc);
+ }
+
+ bfa_ioc_stats(ioc, ioc_hbfails);
+ bfa_fsm_send_event(ioc, IOC_E_HBFAIL);
+}
+
+#else
+
+static void
+bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event)
+{
+}
+
+static void
+bfa_ioc_recover(struct bfa_ioc_s *ioc)
+{
+ bfa_assert(0);
+}
+
+#endif
+
+
diff --git a/drivers/scsi/bfa/bfa_ioc.h b/drivers/scsi/bfa/bfa_ioc.h
new file mode 100644
index 000000000000..7c30f05ab137
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_ioc.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_IOC_H__
+#define __BFA_IOC_H__
+
+#include <cs/bfa_sm.h>
+#include <bfi/bfi.h>
+#include <bfi/bfi_ioc.h>
+#include <bfi/bfi_boot.h>
+#include <bfa_timer.h>
+
+/**
+ * PCI device information required by IOC
+ */
+struct bfa_pcidev_s {
+ int pci_slot;
+ u8 pci_func;
+ u16 device_id;
+ bfa_os_addr_t pci_bar_kva;
+};
+
+/**
+ * Structure used to remember the DMA-able memory block's KVA and Physical
+ * Address
+ */
+struct bfa_dma_s {
+ void *kva; /*! Kernel virtual address */
+ u64 pa; /*! Physical address */
+};
+
+#define BFA_DMA_ALIGN_SZ 256
+#define BFA_ROUNDUP(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1))
+
+
+
+#define bfa_dma_addr_set(dma_addr, pa) \
+ __bfa_dma_addr_set(&dma_addr, (u64)pa)
+
+static inline void
+__bfa_dma_addr_set(union bfi_addr_u *dma_addr, u64 pa)
+{
+ dma_addr->a32.addr_lo = (u32) pa;
+ dma_addr->a32.addr_hi = (u32) (bfa_os_u32(pa));
+}
+
+
+#define bfa_dma_be_addr_set(dma_addr, pa) \
+ __bfa_dma_be_addr_set(&dma_addr, (u64)pa)
+static inline void
+__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa)
+{
+ dma_addr->a32.addr_lo = (u32) bfa_os_htonl(pa);
+ dma_addr->a32.addr_hi = (u32) bfa_os_htonl(bfa_os_u32(pa));
+}
+
+struct bfa_ioc_regs_s {
+ bfa_os_addr_t hfn_mbox_cmd;
+ bfa_os_addr_t hfn_mbox;
+ bfa_os_addr_t lpu_mbox_cmd;
+ bfa_os_addr_t lpu_mbox;
+ bfa_os_addr_t pss_ctl_reg;
+ bfa_os_addr_t app_pll_fast_ctl_reg;
+ bfa_os_addr_t app_pll_slow_ctl_reg;
+ bfa_os_addr_t ioc_sem_reg;
+ bfa_os_addr_t ioc_usage_sem_reg;
+ bfa_os_addr_t ioc_usage_reg;
+ bfa_os_addr_t host_page_num_fn;
+ bfa_os_addr_t heartbeat;
+ bfa_os_addr_t ioc_fwstate;
+ bfa_os_addr_t ll_halt;
+ bfa_os_addr_t shirq_isr_next;
+ bfa_os_addr_t shirq_msk_next;
+ bfa_os_addr_t smem_page_start;
+ u32 smem_pg0;
+};
+
+#define bfa_reg_read(_raddr) bfa_os_reg_read(_raddr)
+#define bfa_reg_write(_raddr, _val) bfa_os_reg_write(_raddr, _val)
+#define bfa_mem_read(_raddr, _off) bfa_os_mem_read(_raddr, _off)
+#define bfa_mem_write(_raddr, _off, _val) \
+ bfa_os_mem_write(_raddr, _off, _val)
+/**
+ * IOC Mailbox structures
+ */
+struct bfa_mbox_cmd_s {
+ struct list_head qe;
+ u32 msg[BFI_IOC_MSGSZ];
+};
+
+/**
+ * IOC mailbox module
+ */
+typedef void (*bfa_ioc_mbox_mcfunc_t)(void *cbarg, struct bfi_mbmsg_s *m);
+struct bfa_ioc_mbox_mod_s {
+ struct list_head cmd_q; /* pending mbox queue */
+ int nmclass; /* number of handlers */
+ struct {
+ bfa_ioc_mbox_mcfunc_t cbfn; /* message handlers */
+ void *cbarg;
+ } mbhdlr[BFI_MC_MAX];
+};
+
+/**
+ * IOC callback function interfaces
+ */
+typedef void (*bfa_ioc_enable_cbfn_t)(void *bfa, enum bfa_status status);
+typedef void (*bfa_ioc_disable_cbfn_t)(void *bfa);
+typedef void (*bfa_ioc_hbfail_cbfn_t)(void *bfa);
+typedef void (*bfa_ioc_reset_cbfn_t)(void *bfa);
+struct bfa_ioc_cbfn_s {
+ bfa_ioc_enable_cbfn_t enable_cbfn;
+ bfa_ioc_disable_cbfn_t disable_cbfn;
+ bfa_ioc_hbfail_cbfn_t hbfail_cbfn;
+ bfa_ioc_reset_cbfn_t reset_cbfn;
+};
+
+/**
+ * Heartbeat failure notification queue element.
+ */
+struct bfa_ioc_hbfail_notify_s {
+ struct list_head qe;
+ bfa_ioc_hbfail_cbfn_t cbfn;
+ void *cbarg;
+};
+
+/**
+ * Initialize a heartbeat failure notification structure
+ */
+#define bfa_ioc_hbfail_init(__notify, __cbfn, __cbarg) do { \
+ (__notify)->cbfn = (__cbfn); \
+ (__notify)->cbarg = (__cbarg); \
+} while (0)
+
+struct bfa_ioc_s {
+ bfa_fsm_t fsm;
+ struct bfa_s *bfa;
+ struct bfa_pcidev_s pcidev;
+ struct bfa_timer_mod_s *timer_mod;
+ struct bfa_timer_s ioc_timer;
+ struct bfa_timer_s sem_timer;
+ u32 hb_count;
+ u32 hb_fail;
+ u32 retry_count;
+ struct list_head hb_notify_q;
+ void *dbg_fwsave;
+ int dbg_fwsave_len;
+ bfa_boolean_t dbg_fwsave_once;
+ enum bfi_mclass ioc_mc;
+ struct bfa_ioc_regs_s ioc_regs;
+ struct bfa_trc_mod_s *trcmod;
+ struct bfa_aen_s *aen;
+ struct bfa_log_mod_s *logm;
+ struct bfa_ioc_drv_stats_s stats;
+ bfa_boolean_t auto_recover;
+ bfa_boolean_t fcmode;
+ bfa_boolean_t ctdev;
+ bfa_boolean_t cna;
+ bfa_boolean_t pllinit;
+ u8 port_id;
+
+ struct bfa_dma_s attr_dma;
+ struct bfi_ioc_attr_s *attr;
+ struct bfa_ioc_cbfn_s *cbfn;
+ 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_portid(__ioc) ((__ioc)->port_id)
+#define bfa_ioc_fetch_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_speed_sup(__ioc) \
+ BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop)
+
+/**
+ * IOC mailbox interface
+ */
+void bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd);
+void bfa_ioc_mbox_register(struct bfa_ioc_s *ioc,
+ bfa_ioc_mbox_mcfunc_t *mcfuncs);
+void bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc);
+void bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len);
+void bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg);
+void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc,
+ bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg);
+
+/**
+ * IOC interfaces
+ */
+void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa,
+ struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod,
+ struct bfa_trc_mod_s *trcmod,
+ struct bfa_aen_s *aen, struct bfa_log_mod_s *logm);
+void bfa_ioc_detach(struct bfa_ioc_s *ioc);
+void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev,
+ enum bfi_mclass mc);
+u32 bfa_ioc_meminfo(void);
+void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa);
+void bfa_ioc_enable(struct bfa_ioc_s *ioc);
+void bfa_ioc_disable(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_intx_claim(struct bfa_ioc_s *ioc);
+
+void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_param);
+void bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *msg);
+void bfa_ioc_error_isr(struct bfa_ioc_s *ioc);
+void bfa_ioc_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t intx);
+bfa_status_t bfa_ioc_pll_init(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc);
+void bfa_ioc_cfg_complete(struct bfa_ioc_s *ioc);
+void bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr);
+void bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc,
+ struct bfa_adapter_attr_s *ad_attr);
+int bfa_ioc_debug_trcsz(bfa_boolean_t auto_recover);
+void bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave);
+bfa_status_t bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata,
+ int *trclen);
+bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata,
+ int *trclen);
+u32 bfa_ioc_smem_pgnum(struct bfa_ioc_s *ioc, u32 fmaddr);
+u32 bfa_ioc_smem_pgoff(struct bfa_ioc_s *ioc, u32 fmaddr);
+void bfa_ioc_set_fcmode(struct bfa_ioc_s *ioc);
+bfa_boolean_t bfa_ioc_get_fcmode(struct bfa_ioc_s *ioc);
+void bfa_ioc_hbfail_register(struct bfa_ioc_s *ioc,
+ struct bfa_ioc_hbfail_notify_s *notify);
+
+/*
+ * bfa mfg wwn API functions
+ */
+wwn_t bfa_ioc_get_pwwn(struct bfa_ioc_s *ioc);
+wwn_t bfa_ioc_get_nwwn(struct bfa_ioc_s *ioc);
+wwn_t bfa_ioc_get_wwn_naa5(struct bfa_ioc_s *ioc, u16 inst);
+mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc);
+u64 bfa_ioc_get_adid(struct bfa_ioc_s *ioc);
+
+#endif /* __BFA_IOC_H__ */
+
diff --git a/drivers/scsi/bfa/bfa_iocfc.c b/drivers/scsi/bfa/bfa_iocfc.c
new file mode 100644
index 000000000000..d7ab792a9e54
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_iocfc.c
@@ -0,0 +1,872 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <cs/bfa_debug.h>
+#include <bfa_priv.h>
+#include <log/bfa_log_hal.h>
+#include <bfi/bfi_boot.h>
+#include <bfi/bfi_cbreg.h>
+#include <aen/bfa_aen_ioc.h>
+#include <defs/bfa_defs_iocfc.h>
+#include <defs/bfa_defs_pci.h>
+#include "bfa_callback_priv.h"
+#include "bfad_drv.h"
+
+BFA_TRC_FILE(HAL, IOCFC);
+
+/**
+ * IOC local definitions
+ */
+#define BFA_IOCFC_TOV 5000 /* msecs */
+
+enum {
+ BFA_IOCFC_ACT_NONE = 0,
+ BFA_IOCFC_ACT_INIT = 1,
+ BFA_IOCFC_ACT_STOP = 2,
+ BFA_IOCFC_ACT_DISABLE = 3,
+};
+
+/*
+ * forward declarations
+ */
+static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status);
+static void bfa_iocfc_disable_cbfn(void *bfa_arg);
+static void bfa_iocfc_hbfail_cbfn(void *bfa_arg);
+static void bfa_iocfc_reset_cbfn(void *bfa_arg);
+static void bfa_iocfc_stats_clear(void *bfa_arg);
+static void bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d,
+ struct bfa_fw_stats_s *s);
+static void bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete);
+static void bfa_iocfc_stats_clr_timeout(void *bfa_arg);
+static void bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete);
+static void bfa_iocfc_stats_timeout(void *bfa_arg);
+
+static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn;
+
+/**
+ * bfa_ioc_pvt BFA IOC private functions
+ */
+
+static void
+bfa_iocfc_cqs_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len)
+{
+ int i, per_reqq_sz, per_rspq_sz;
+
+ per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ),
+ BFA_DMA_ALIGN_SZ);
+ per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ),
+ BFA_DMA_ALIGN_SZ);
+
+ /*
+ * Calculate CQ size
+ */
+ for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
+ *dm_len = *dm_len + per_reqq_sz;
+ *dm_len = *dm_len + per_rspq_sz;
+ }
+
+ /*
+ * Calculate Shadow CI/PI size
+ */
+ for (i = 0; i < cfg->fwcfg.num_cqs; i++)
+ *dm_len += (2 * BFA_CACHELINE_SZ);
+}
+
+static void
+bfa_iocfc_fw_cfg_sz(struct bfa_iocfc_cfg_s *cfg, u32 *dm_len)
+{
+ *dm_len +=
+ BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
+ *dm_len +=
+ BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
+ BFA_CACHELINE_SZ);
+ *dm_len += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
+}
+
+/**
+ * Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ
+ */
+static void
+bfa_iocfc_send_cfg(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfg_req_s cfg_req;
+ struct bfi_iocfc_cfg_s *cfg_info = iocfc->cfginfo;
+ struct bfa_iocfc_cfg_s *cfg = &iocfc->cfg;
+ int i;
+
+ bfa_assert(cfg->fwcfg.num_cqs <= BFI_IOC_MAX_CQS);
+ bfa_trc(bfa, cfg->fwcfg.num_cqs);
+
+ iocfc->cfgdone = BFA_FALSE;
+ bfa_iocfc_reset_queues(bfa);
+
+ /**
+ * initialize IOC configuration info
+ */
+ cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG;
+ cfg_info->num_cqs = cfg->fwcfg.num_cqs;
+
+ bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa);
+ bfa_dma_be_addr_set(cfg_info->stats_addr, iocfc->stats_pa);
+
+ /**
+ * dma map REQ and RSP circular queues and shadow pointers
+ */
+ for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
+ bfa_dma_be_addr_set(cfg_info->req_cq_ba[i],
+ iocfc->req_cq_ba[i].pa);
+ bfa_dma_be_addr_set(cfg_info->req_shadow_ci[i],
+ iocfc->req_cq_shadow_ci[i].pa);
+ cfg_info->req_cq_elems[i] =
+ bfa_os_htons(cfg->drvcfg.num_reqq_elems);
+
+ bfa_dma_be_addr_set(cfg_info->rsp_cq_ba[i],
+ iocfc->rsp_cq_ba[i].pa);
+ bfa_dma_be_addr_set(cfg_info->rsp_shadow_pi[i],
+ iocfc->rsp_cq_shadow_pi[i].pa);
+ cfg_info->rsp_cq_elems[i] =
+ bfa_os_htons(cfg->drvcfg.num_rspq_elems);
+ }
+
+ /**
+ * dma map IOC configuration itself
+ */
+ bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ,
+ bfa_lpuid(bfa));
+ bfa_dma_be_addr_set(cfg_req.ioc_cfg_dma_addr, iocfc->cfg_info.pa);
+
+ bfa_ioc_mbox_send(&bfa->ioc, &cfg_req,
+ sizeof(struct bfi_iocfc_cfg_req_s));
+}
+
+static void
+bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ bfa->bfad = bfad;
+ iocfc->bfa = bfa;
+ iocfc->action = BFA_IOCFC_ACT_NONE;
+
+ bfa_os_assign(iocfc->cfg, *cfg);
+
+ /**
+ * Initialize chip specific handlers.
+ */
+ if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) {
+ iocfc->hwif.hw_reginit = bfa_hwct_reginit;
+ iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack;
+ iocfc->hwif.hw_msix_init = bfa_hwct_msix_init;
+ iocfc->hwif.hw_msix_install = bfa_hwct_msix_install;
+ iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall;
+ iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set;
+ iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs;
+ } else {
+ iocfc->hwif.hw_reginit = bfa_hwcb_reginit;
+ iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack;
+ iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init;
+ iocfc->hwif.hw_msix_install = bfa_hwcb_msix_install;
+ iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall;
+ iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set;
+ iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs;
+ }
+
+ iocfc->hwif.hw_reginit(bfa);
+ bfa->msix.nvecs = 0;
+}
+
+static void
+bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo)
+{
+ u8 *dm_kva;
+ u64 dm_pa;
+ int i, per_reqq_sz, per_rspq_sz;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ int dbgsz;
+
+ dm_kva = bfa_meminfo_dma_virt(meminfo);
+ dm_pa = bfa_meminfo_dma_phys(meminfo);
+
+ /*
+ * First allocate dma memory for IOC.
+ */
+ bfa_ioc_mem_claim(&bfa->ioc, dm_kva, dm_pa);
+ dm_kva += bfa_ioc_meminfo();
+ dm_pa += bfa_ioc_meminfo();
+
+ /*
+ * Claim DMA-able memory for the request/response queues and for shadow
+ * ci/pi registers
+ */
+ per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ),
+ BFA_DMA_ALIGN_SZ);
+ per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ),
+ BFA_DMA_ALIGN_SZ);
+
+ for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
+ iocfc->req_cq_ba[i].kva = dm_kva;
+ iocfc->req_cq_ba[i].pa = dm_pa;
+ bfa_os_memset(dm_kva, 0, per_reqq_sz);
+ dm_kva += per_reqq_sz;
+ dm_pa += per_reqq_sz;
+
+ iocfc->rsp_cq_ba[i].kva = dm_kva;
+ iocfc->rsp_cq_ba[i].pa = dm_pa;
+ bfa_os_memset(dm_kva, 0, per_rspq_sz);
+ dm_kva += per_rspq_sz;
+ dm_pa += per_rspq_sz;
+ }
+
+ for (i = 0; i < cfg->fwcfg.num_cqs; i++) {
+ iocfc->req_cq_shadow_ci[i].kva = dm_kva;
+ iocfc->req_cq_shadow_ci[i].pa = dm_pa;
+ dm_kva += BFA_CACHELINE_SZ;
+ dm_pa += BFA_CACHELINE_SZ;
+
+ iocfc->rsp_cq_shadow_pi[i].kva = dm_kva;
+ iocfc->rsp_cq_shadow_pi[i].pa = dm_pa;
+ dm_kva += BFA_CACHELINE_SZ;
+ dm_pa += BFA_CACHELINE_SZ;
+ }
+
+ /*
+ * Claim DMA-able memory for the config info page
+ */
+ bfa->iocfc.cfg_info.kva = dm_kva;
+ bfa->iocfc.cfg_info.pa = dm_pa;
+ bfa->iocfc.cfginfo = (struct bfi_iocfc_cfg_s *) dm_kva;
+ dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
+ dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ);
+
+ /*
+ * Claim DMA-able memory for the config response
+ */
+ bfa->iocfc.cfgrsp_dma.kva = dm_kva;
+ bfa->iocfc.cfgrsp_dma.pa = dm_pa;
+ bfa->iocfc.cfgrsp = (struct bfi_iocfc_cfgrsp_s *) dm_kva;
+
+ dm_kva +=
+ BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
+ BFA_CACHELINE_SZ);
+ dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s),
+ BFA_CACHELINE_SZ);
+
+ /*
+ * Claim DMA-able memory for iocfc stats
+ */
+ bfa->iocfc.stats_kva = dm_kva;
+ bfa->iocfc.stats_pa = dm_pa;
+ bfa->iocfc.fw_stats = (struct bfa_fw_stats_s *) dm_kva;
+ dm_kva += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
+ dm_pa += BFA_ROUNDUP(sizeof(struct bfa_fw_stats_s), BFA_CACHELINE_SZ);
+
+ bfa_meminfo_dma_virt(meminfo) = dm_kva;
+ bfa_meminfo_dma_phys(meminfo) = dm_pa;
+
+ dbgsz = bfa_ioc_debug_trcsz(bfa_auto_recover);
+ if (dbgsz > 0) {
+ bfa_ioc_debug_memclaim(&bfa->ioc, bfa_meminfo_kva(meminfo));
+ bfa_meminfo_kva(meminfo) += dbgsz;
+ }
+}
+
+/**
+ * BFA submodules initialization completion notification.
+ */
+static void
+bfa_iocfc_initdone_submod(struct bfa_s *bfa)
+{
+ int i;
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->initdone(bfa);
+}
+
+/**
+ * Start BFA submodules.
+ */
+static void
+bfa_iocfc_start_submod(struct bfa_s *bfa)
+{
+ int i;
+
+ bfa->rme_process = BFA_TRUE;
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->start(bfa);
+}
+
+/**
+ * Disable BFA submodules.
+ */
+static void
+bfa_iocfc_disable_submod(struct bfa_s *bfa)
+{
+ int i;
+
+ for (i = 0; hal_mods[i]; i++)
+ hal_mods[i]->iocdisable(bfa);
+}
+
+static void
+bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete)
+{
+ struct bfa_s *bfa = bfa_arg;
+
+ if (complete) {
+ if (bfa->iocfc.cfgdone)
+ bfa_cb_init(bfa->bfad, BFA_STATUS_OK);
+ else
+ bfa_cb_init(bfa->bfad, BFA_STATUS_FAILED);
+ } else
+ bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
+}
+
+static void
+bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfad_s *bfad = bfa->bfad;
+
+ if (compl)
+ complete(&bfad->comp);
+
+ else
+ bfa->iocfc.action = BFA_IOCFC_ACT_NONE;
+}
+
+static void
+bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfad_s *bfad = bfa->bfad;
+
+ if (compl)
+ complete(&bfad->disable_comp);
+}
+
+/**
+ * Update BFA configuration from firmware configuration.
+ */
+static void
+bfa_iocfc_cfgrsp(struct bfa_s *bfa)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+ struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg;
+ struct bfi_iocfc_cfg_s *cfginfo = iocfc->cfginfo;
+
+ fwcfg->num_cqs = fwcfg->num_cqs;
+ fwcfg->num_ioim_reqs = bfa_os_ntohs(fwcfg->num_ioim_reqs);
+ fwcfg->num_tskim_reqs = bfa_os_ntohs(fwcfg->num_tskim_reqs);
+ fwcfg->num_fcxp_reqs = bfa_os_ntohs(fwcfg->num_fcxp_reqs);
+ fwcfg->num_uf_bufs = bfa_os_ntohs(fwcfg->num_uf_bufs);
+ fwcfg->num_rports = bfa_os_ntohs(fwcfg->num_rports);
+
+ cfginfo->intr_attr.coalesce = cfgrsp->intr_attr.coalesce;
+ cfginfo->intr_attr.delay = bfa_os_ntohs(cfgrsp->intr_attr.delay);
+ cfginfo->intr_attr.latency = bfa_os_ntohs(cfgrsp->intr_attr.latency);
+
+ iocfc->cfgdone = BFA_TRUE;
+
+ /**
+ * Configuration is complete - initialize/start submodules
+ */
+ if (iocfc->action == BFA_IOCFC_ACT_INIT)
+ bfa_cb_queue(bfa, &iocfc->init_hcb_qe, bfa_iocfc_init_cb, bfa);
+ else
+ bfa_iocfc_start_submod(bfa);
+}
+
+static void
+bfa_iocfc_stats_clear(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_stats_req_s stats_req;
+
+ bfa_timer_start(bfa, &iocfc->stats_timer,
+ bfa_iocfc_stats_clr_timeout, bfa,
+ BFA_IOCFC_TOV);
+
+ bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CLEAR_STATS_REQ,
+ bfa_lpuid(bfa));
+ bfa_ioc_mbox_send(&bfa->ioc, &stats_req,
+ sizeof(struct bfi_iocfc_stats_req_s));
+}
+
+static void
+bfa_iocfc_stats_swap(struct bfa_fw_stats_s *d, struct bfa_fw_stats_s *s)
+{
+ u32 *dip = (u32 *) d;
+ u32 *sip = (u32 *) s;
+ int i;
+
+ for (i = 0; i < (sizeof(struct bfa_fw_stats_s) / sizeof(u32)); i++)
+ dip[i] = bfa_os_ntohl(sip[i]);
+}
+
+static void
+bfa_iocfc_stats_clr_cb(void *bfa_arg, bfa_boolean_t complete)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ if (complete) {
+ bfa_ioc_clr_stats(&bfa->ioc);
+ iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status);
+ } else {
+ iocfc->stats_busy = BFA_FALSE;
+ iocfc->stats_status = BFA_STATUS_OK;
+ }
+}
+
+static void
+bfa_iocfc_stats_clr_timeout(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ bfa_trc(bfa, 0);
+
+ iocfc->stats_status = BFA_STATUS_ETIMER;
+ bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_clr_cb, bfa);
+}
+
+static void
+bfa_iocfc_stats_cb(void *bfa_arg, bfa_boolean_t complete)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ if (complete) {
+ if (iocfc->stats_status == BFA_STATUS_OK) {
+ bfa_os_memset(iocfc->stats_ret, 0,
+ sizeof(*iocfc->stats_ret));
+ bfa_iocfc_stats_swap(&iocfc->stats_ret->fw_stats,
+ iocfc->fw_stats);
+ }
+ iocfc->stats_cbfn(iocfc->stats_cbarg, iocfc->stats_status);
+ } else {
+ iocfc->stats_busy = BFA_FALSE;
+ iocfc->stats_status = BFA_STATUS_OK;
+ }
+}
+
+static void
+bfa_iocfc_stats_timeout(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ bfa_trc(bfa, 0);
+
+ iocfc->stats_status = BFA_STATUS_ETIMER;
+ bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb, bfa);
+}
+
+static void
+bfa_iocfc_stats_query(struct bfa_s *bfa)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_stats_req_s stats_req;
+
+ bfa_timer_start(bfa, &iocfc->stats_timer,
+ bfa_iocfc_stats_timeout, bfa, BFA_IOCFC_TOV);
+
+ bfi_h2i_set(stats_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_GET_STATS_REQ,
+ bfa_lpuid(bfa));
+ bfa_ioc_mbox_send(&bfa->ioc, &stats_req,
+ sizeof(struct bfi_iocfc_stats_req_s));
+}
+
+void
+bfa_iocfc_reset_queues(struct bfa_s *bfa)
+{
+ int q;
+
+ for (q = 0; q < BFI_IOC_MAX_CQS; q++) {
+ bfa_reqq_ci(bfa, q) = 0;
+ bfa_reqq_pi(bfa, q) = 0;
+ bfa_rspq_ci(bfa, q) = 0;
+ bfa_rspq_pi(bfa, q) = 0;
+ }
+}
+
+/**
+ * IOC enable request is complete
+ */
+static void
+bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status)
+{
+ struct bfa_s *bfa = bfa_arg;
+
+ if (status != BFA_STATUS_OK) {
+ bfa_isr_disable(bfa);
+ if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT)
+ bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe,
+ bfa_iocfc_init_cb, bfa);
+ return;
+ }
+
+ bfa_iocfc_initdone_submod(bfa);
+ bfa_iocfc_send_cfg(bfa);
+}
+
+/**
+ * IOC disable request is complete
+ */
+static void
+bfa_iocfc_disable_cbfn(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+
+ bfa_isr_disable(bfa);
+ bfa_iocfc_disable_submod(bfa);
+
+ if (bfa->iocfc.action == BFA_IOCFC_ACT_STOP)
+ bfa_cb_queue(bfa, &bfa->iocfc.stop_hcb_qe, bfa_iocfc_stop_cb,
+ bfa);
+ else {
+ bfa_assert(bfa->iocfc.action == BFA_IOCFC_ACT_DISABLE);
+ bfa_cb_queue(bfa, &bfa->iocfc.dis_hcb_qe, bfa_iocfc_disable_cb,
+ bfa);
+ }
+}
+
+/**
+ * Notify sub-modules of hardware failure.
+ */
+static void
+bfa_iocfc_hbfail_cbfn(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+
+ bfa->rme_process = BFA_FALSE;
+
+ bfa_isr_disable(bfa);
+ bfa_iocfc_disable_submod(bfa);
+
+ if (bfa->iocfc.action == BFA_IOCFC_ACT_INIT)
+ bfa_cb_queue(bfa, &bfa->iocfc.init_hcb_qe, bfa_iocfc_init_cb,
+ bfa);
+}
+
+/**
+ * Actions on chip-reset completion.
+ */
+static void
+bfa_iocfc_reset_cbfn(void *bfa_arg)
+{
+ struct bfa_s *bfa = bfa_arg;
+
+ bfa_iocfc_reset_queues(bfa);
+ bfa_isr_enable(bfa);
+}
+
+
+
+/**
+ * bfa_ioc_public
+ */
+
+/**
+ * Query IOC memory requirement information.
+ */
+void
+bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len)
+{
+ /* dma memory for IOC */
+ *dm_len += bfa_ioc_meminfo();
+
+ bfa_iocfc_fw_cfg_sz(cfg, dm_len);
+ bfa_iocfc_cqs_sz(cfg, dm_len);
+ *km_len += bfa_ioc_debug_trcsz(bfa_auto_recover);
+}
+
+/**
+ * Query IOC memory requirement information.
+ */
+void
+bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ int i;
+
+ bfa_iocfc_cbfn.enable_cbfn = bfa_iocfc_enable_cbfn;
+ bfa_iocfc_cbfn.disable_cbfn = bfa_iocfc_disable_cbfn;
+ bfa_iocfc_cbfn.hbfail_cbfn = bfa_iocfc_hbfail_cbfn;
+ bfa_iocfc_cbfn.reset_cbfn = bfa_iocfc_reset_cbfn;
+
+ bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod,
+ bfa->trcmod, bfa->aen, bfa->logm);
+ bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_MC_IOCFC);
+ bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs);
+
+ /**
+ * Choose FC (ssid: 0x1C) v/s FCoE (ssid: 0x14) mode.
+ */
+ if (0)
+ bfa_ioc_set_fcmode(&bfa->ioc);
+
+ bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev);
+ bfa_iocfc_mem_claim(bfa, cfg, meminfo);
+ bfa_timer_init(&bfa->timer_mod);
+
+ INIT_LIST_HEAD(&bfa->comp_q);
+ for (i = 0; i < BFI_IOC_MAX_CQS; i++)
+ INIT_LIST_HEAD(&bfa->reqq_waitq[i]);
+}
+
+/**
+ * Query IOC memory requirement information.
+ */
+void
+bfa_iocfc_detach(struct bfa_s *bfa)
+{
+ bfa_ioc_detach(&bfa->ioc);
+}
+
+/**
+ * Query IOC memory requirement information.
+ */
+void
+bfa_iocfc_init(struct bfa_s *bfa)
+{
+ bfa->iocfc.action = BFA_IOCFC_ACT_INIT;
+ bfa_ioc_enable(&bfa->ioc);
+ bfa_msix_install(bfa);
+}
+
+/**
+ * IOC start called from bfa_start(). Called to start IOC operations
+ * at driver instantiation for this instance.
+ */
+void
+bfa_iocfc_start(struct bfa_s *bfa)
+{
+ if (bfa->iocfc.cfgdone)
+ bfa_iocfc_start_submod(bfa);
+}
+
+/**
+ * IOC stop called from bfa_stop(). Called only when driver is unloaded
+ * for this instance.
+ */
+void
+bfa_iocfc_stop(struct bfa_s *bfa)
+{
+ bfa->iocfc.action = BFA_IOCFC_ACT_STOP;
+
+ bfa->rme_process = BFA_FALSE;
+ bfa_ioc_disable(&bfa->ioc);
+}
+
+void
+bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m)
+{
+ struct bfa_s *bfa = bfaarg;
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ union bfi_iocfc_i2h_msg_u *msg;
+
+ msg = (union bfi_iocfc_i2h_msg_u *) m;
+ bfa_trc(bfa, msg->mh.msg_id);
+
+ switch (msg->mh.msg_id) {
+ case BFI_IOCFC_I2H_CFG_REPLY:
+ iocfc->cfg_reply = &msg->cfg_reply;
+ bfa_iocfc_cfgrsp(bfa);
+ break;
+
+ case BFI_IOCFC_I2H_GET_STATS_RSP:
+ if (iocfc->stats_busy == BFA_FALSE
+ || iocfc->stats_status == BFA_STATUS_ETIMER)
+ break;
+
+ bfa_timer_stop(&iocfc->stats_timer);
+ iocfc->stats_status = BFA_STATUS_OK;
+ bfa_cb_queue(bfa, &iocfc->stats_hcb_qe, bfa_iocfc_stats_cb,
+ bfa);
+ break;
+ case BFI_IOCFC_I2H_CLEAR_STATS_RSP:
+ /*
+ * check for timer pop before processing the rsp
+ */
+ if (iocfc->stats_busy == BFA_FALSE
+ || iocfc->stats_status == BFA_STATUS_ETIMER)
+ break;
+
+ bfa_timer_stop(&iocfc->stats_timer);
+ iocfc->stats_status = BFA_STATUS_OK;
+ bfa_cb_queue(bfa, &iocfc->stats_hcb_qe,
+ bfa_iocfc_stats_clr_cb, bfa);
+ break;
+ case BFI_IOCFC_I2H_UPDATEQ_RSP:
+ iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK);
+ break;
+ default:
+ bfa_assert(0);
+ }
+}
+
+#ifndef BFA_BIOS_BUILD
+void
+bfa_adapter_get_attr(struct bfa_s *bfa, struct bfa_adapter_attr_s *ad_attr)
+{
+ bfa_ioc_get_adapter_attr(&bfa->ioc, ad_attr);
+}
+
+u64
+bfa_adapter_get_id(struct bfa_s *bfa)
+{
+ return bfa_ioc_get_adid(&bfa->ioc);
+}
+
+void
+bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ attr->intr_attr = iocfc->cfginfo->intr_attr;
+ attr->config = iocfc->cfg;
+}
+
+bfa_status_t
+bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_set_intr_req_s *m;
+
+ iocfc->cfginfo->intr_attr = *attr;
+ if (!bfa_iocfc_is_operational(bfa))
+ return BFA_STATUS_OK;
+
+ m = bfa_reqq_next(bfa, BFA_REQQ_IOC);
+ if (!m)
+ return BFA_STATUS_DEVBUSY;
+
+ bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ,
+ bfa_lpuid(bfa));
+ m->coalesce = attr->coalesce;
+ m->delay = bfa_os_htons(attr->delay);
+ m->latency = bfa_os_htons(attr->latency);
+
+ bfa_trc(bfa, attr->delay);
+ bfa_trc(bfa, attr->latency);
+
+ bfa_reqq_produce(bfa, BFA_REQQ_IOC);
+ return BFA_STATUS_OK;
+}
+
+void
+bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1);
+ bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase, snsbase_pa);
+}
+
+bfa_status_t
+bfa_iocfc_get_stats(struct bfa_s *bfa, struct bfa_iocfc_stats_s *stats,
+ bfa_cb_ioc_t cbfn, void *cbarg)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ if (iocfc->stats_busy) {
+ bfa_trc(bfa, iocfc->stats_busy);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ iocfc->stats_busy = BFA_TRUE;
+ iocfc->stats_ret = stats;
+ iocfc->stats_cbfn = cbfn;
+ iocfc->stats_cbarg = cbarg;
+
+ bfa_iocfc_stats_query(bfa);
+
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_iocfc_clear_stats(struct bfa_s *bfa, bfa_cb_ioc_t cbfn, void *cbarg)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+
+ if (iocfc->stats_busy) {
+ bfa_trc(bfa, iocfc->stats_busy);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ iocfc->stats_busy = BFA_TRUE;
+ iocfc->stats_cbfn = cbfn;
+ iocfc->stats_cbarg = cbarg;
+
+ bfa_iocfc_stats_clear(bfa);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Enable IOC after it is disabled.
+ */
+void
+bfa_iocfc_enable(struct bfa_s *bfa)
+{
+ bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0,
+ "IOC Enable");
+ bfa_ioc_enable(&bfa->ioc);
+}
+
+void
+bfa_iocfc_disable(struct bfa_s *bfa)
+{
+ bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0,
+ "IOC Disable");
+ bfa->iocfc.action = BFA_IOCFC_ACT_DISABLE;
+
+ bfa->rme_process = BFA_FALSE;
+ bfa_ioc_disable(&bfa->ioc);
+}
+
+
+bfa_boolean_t
+bfa_iocfc_is_operational(struct bfa_s *bfa)
+{
+ return bfa_ioc_is_operational(&bfa->ioc) && bfa->iocfc.cfgdone;
+}
+
+/**
+ * Return boot target port wwns -- read from boot information in flash.
+ */
+void
+bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp;
+
+ *nwwns = cfgrsp->bootwwns.nwwns;
+ *wwns = cfgrsp->bootwwns.wwn;
+}
+
+#endif
+
+
diff --git a/drivers/scsi/bfa/bfa_iocfc.h b/drivers/scsi/bfa/bfa_iocfc.h
new file mode 100644
index 000000000000..ce9a830a4207
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_iocfc.h
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_IOCFC_H__
+#define __BFA_IOCFC_H__
+
+#include <bfa_ioc.h>
+#include <bfa.h>
+#include <bfi/bfi_iocfc.h>
+#include <bfa_callback_priv.h>
+
+#define BFA_REQQ_NELEMS_MIN (4)
+#define BFA_RSPQ_NELEMS_MIN (4)
+
+struct bfa_iocfc_regs_s {
+ bfa_os_addr_t intr_status;
+ bfa_os_addr_t intr_mask;
+ bfa_os_addr_t cpe_q_pi[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t cpe_q_ci[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t cpe_q_depth[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t cpe_q_ctrl[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t rme_q_ci[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t rme_q_pi[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t rme_q_depth[BFI_IOC_MAX_CQS];
+ bfa_os_addr_t rme_q_ctrl[BFI_IOC_MAX_CQS];
+};
+
+/**
+ * MSIX vector handlers
+ */
+#define BFA_MSIX_MAX_VECTORS 22
+typedef void (*bfa_msix_handler_t)(struct bfa_s *bfa, int vec);
+struct bfa_msix_s {
+ int nvecs;
+ bfa_msix_handler_t handler[BFA_MSIX_MAX_VECTORS];
+};
+
+/**
+ * Chip specific interfaces
+ */
+struct bfa_hwif_s {
+ void (*hw_reginit)(struct bfa_s *bfa);
+ void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq);
+ void (*hw_msix_init)(struct bfa_s *bfa, int nvecs);
+ void (*hw_msix_install)(struct bfa_s *bfa);
+ void (*hw_msix_uninstall)(struct bfa_s *bfa);
+ void (*hw_isr_mode_set)(struct bfa_s *bfa, bfa_boolean_t msix);
+ void (*hw_msix_getvecs)(struct bfa_s *bfa, u32 *vecmap,
+ u32 *nvecs, u32 *maxvec);
+};
+typedef void (*bfa_cb_iocfc_t) (void *cbarg, enum bfa_status status);
+
+struct bfa_iocfc_s {
+ struct bfa_s *bfa;
+ struct bfa_iocfc_cfg_s cfg;
+ int action;
+
+ u32 req_cq_pi[BFI_IOC_MAX_CQS];
+ u32 rsp_cq_ci[BFI_IOC_MAX_CQS];
+
+ struct bfa_cb_qe_s init_hcb_qe;
+ struct bfa_cb_qe_s stop_hcb_qe;
+ struct bfa_cb_qe_s dis_hcb_qe;
+ struct bfa_cb_qe_s stats_hcb_qe;
+ bfa_boolean_t cfgdone;
+
+ struct bfa_dma_s cfg_info;
+ struct bfi_iocfc_cfg_s *cfginfo;
+ struct bfa_dma_s cfgrsp_dma;
+ struct bfi_iocfc_cfgrsp_s *cfgrsp;
+ struct bfi_iocfc_cfg_reply_s *cfg_reply;
+
+ u8 *stats_kva;
+ u64 stats_pa;
+ struct bfa_fw_stats_s *fw_stats;
+ struct bfa_timer_s stats_timer; /* timer */
+ struct bfa_iocfc_stats_s *stats_ret; /* driver stats location */
+ bfa_status_t stats_status; /* stats/statsclr status */
+ bfa_boolean_t stats_busy; /* outstanding stats */
+ bfa_cb_ioc_t stats_cbfn; /* driver callback function */
+ void *stats_cbarg; /* user callback arg */
+
+ struct bfa_dma_s req_cq_ba[BFI_IOC_MAX_CQS];
+ struct bfa_dma_s req_cq_shadow_ci[BFI_IOC_MAX_CQS];
+ struct bfa_dma_s rsp_cq_ba[BFI_IOC_MAX_CQS];
+ struct bfa_dma_s rsp_cq_shadow_pi[BFI_IOC_MAX_CQS];
+ struct bfa_iocfc_regs_s bfa_regs; /* BFA device registers */
+ struct bfa_hwif_s hwif;
+
+ bfa_cb_iocfc_t updateq_cbfn; /* bios callback function */
+ void *updateq_cbarg; /* bios callback arg */
+};
+
+#define bfa_lpuid(__bfa) bfa_ioc_portid(&(__bfa)->ioc)
+#define bfa_msix_init(__bfa, __nvecs) \
+ ((__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs))
+#define bfa_msix_install(__bfa) \
+ ((__bfa)->iocfc.hwif.hw_msix_install(__bfa))
+#define bfa_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))
+#define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \
+ (__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec)
+
+/*
+ * FC specific IOC functions.
+ */
+void bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len);
+void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad,
+ struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo,
+ struct bfa_pcidev_s *pcidev);
+void bfa_iocfc_detach(struct bfa_s *bfa);
+void bfa_iocfc_init(struct bfa_s *bfa);
+void bfa_iocfc_start(struct bfa_s *bfa);
+void bfa_iocfc_stop(struct bfa_s *bfa);
+void bfa_iocfc_isr(void *bfa, struct bfi_mbmsg_s *msg);
+void bfa_iocfc_set_snsbase(struct bfa_s *bfa, u64 snsbase_pa);
+bfa_boolean_t bfa_iocfc_is_operational(struct bfa_s *bfa);
+void bfa_iocfc_reset_queues(struct bfa_s *bfa);
+void bfa_iocfc_updateq(struct bfa_s *bfa, u32 reqq_ba, u32 rspq_ba,
+ u32 reqq_sci, u32 rspq_spi,
+ bfa_cb_iocfc_t cbfn, void *cbarg);
+
+void bfa_msix_all(struct bfa_s *bfa, int vec);
+void bfa_msix_reqq(struct bfa_s *bfa, int vec);
+void bfa_msix_rspq(struct bfa_s *bfa, int vec);
+void bfa_msix_lpu_err(struct bfa_s *bfa, int vec);
+
+void bfa_hwcb_reginit(struct bfa_s *bfa);
+void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq);
+void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs);
+void bfa_hwcb_msix_install(struct bfa_s *bfa);
+void bfa_hwcb_msix_uninstall(struct bfa_s *bfa);
+void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix);
+void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap,
+ u32 *nvecs, u32 *maxvec);
+void bfa_hwct_reginit(struct bfa_s *bfa);
+void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq);
+void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs);
+void bfa_hwct_msix_install(struct bfa_s *bfa);
+void bfa_hwct_msix_uninstall(struct bfa_s *bfa);
+void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix);
+void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap,
+ u32 *nvecs, u32 *maxvec);
+
+void bfa_com_meminfo(bfa_boolean_t mincfg, u32 *dm_len);
+void bfa_com_attach(struct bfa_s *bfa, struct bfa_meminfo_s *mi,
+ bfa_boolean_t mincfg);
+void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t **wwns);
+
+#endif /* __BFA_IOCFC_H__ */
+
diff --git a/drivers/scsi/bfa/bfa_iocfc_q.c b/drivers/scsi/bfa/bfa_iocfc_q.c
new file mode 100644
index 000000000000..500a17df40b2
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_iocfc_q.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include "bfa_intr_priv.h"
+
+BFA_TRC_FILE(HAL, IOCFC_Q);
+
+void
+bfa_iocfc_updateq(struct bfa_s *bfa, u32 reqq_ba, u32 rspq_ba,
+ u32 reqq_sci, u32 rspq_spi, bfa_cb_iocfc_t cbfn,
+ void *cbarg)
+{
+ struct bfa_iocfc_s *iocfc = &bfa->iocfc;
+ struct bfi_iocfc_updateq_req_s updateq_req;
+
+ iocfc->updateq_cbfn = cbfn;
+ iocfc->updateq_cbarg = cbarg;
+
+ bfi_h2i_set(updateq_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_UPDATEQ_REQ,
+ bfa_lpuid(bfa));
+
+ updateq_req.reqq_ba = bfa_os_htonl(reqq_ba);
+ updateq_req.rspq_ba = bfa_os_htonl(rspq_ba);
+ updateq_req.reqq_sci = bfa_os_htonl(reqq_sci);
+ updateq_req.rspq_spi = bfa_os_htonl(rspq_spi);
+
+ bfa_ioc_mbox_send(&bfa->ioc, &updateq_req,
+ sizeof(struct bfi_iocfc_updateq_req_s));
+}
diff --git a/drivers/scsi/bfa/bfa_ioim.c b/drivers/scsi/bfa/bfa_ioim.c
new file mode 100644
index 000000000000..f81d359b7089
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_ioim.c
@@ -0,0 +1,1311 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <cs/bfa_debug.h>
+#include <bfa_cb_ioim_macros.h>
+
+BFA_TRC_FILE(HAL, IOIM);
+
+/*
+ * forward declarations.
+ */
+static bfa_boolean_t bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim);
+static bfa_boolean_t bfa_ioim_sge_setup(struct bfa_ioim_s *ioim);
+static void bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim);
+static bfa_boolean_t bfa_ioim_send_abort(struct bfa_ioim_s *ioim);
+static void bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim);
+static void __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete);
+
+/**
+ * bfa_ioim_sm
+ */
+
+/**
+ * IO state machine events
+ */
+enum bfa_ioim_event {
+ BFA_IOIM_SM_START = 1, /* io start request from host */
+ BFA_IOIM_SM_COMP_GOOD = 2, /* io good comp, resource free */
+ BFA_IOIM_SM_COMP = 3, /* io comp, resource is free */
+ BFA_IOIM_SM_COMP_UTAG = 4, /* io comp, resource is free */
+ BFA_IOIM_SM_DONE = 5, /* io comp, resource not free */
+ BFA_IOIM_SM_FREE = 6, /* io resource is freed */
+ BFA_IOIM_SM_ABORT = 7, /* abort request from scsi stack */
+ BFA_IOIM_SM_ABORT_COMP = 8, /* abort from f/w */
+ BFA_IOIM_SM_ABORT_DONE = 9, /* abort completion from f/w */
+ BFA_IOIM_SM_QRESUME = 10, /* CQ space available to queue IO */
+ BFA_IOIM_SM_SGALLOCED = 11, /* SG page allocation successful */
+ BFA_IOIM_SM_SQRETRY = 12, /* sequence recovery retry */
+ BFA_IOIM_SM_HCB = 13, /* bfa callback complete */
+ BFA_IOIM_SM_CLEANUP = 14, /* IO cleanup from itnim */
+ BFA_IOIM_SM_TMSTART = 15, /* IO cleanup from tskim */
+ BFA_IOIM_SM_TMDONE = 16, /* IO cleanup from tskim */
+ BFA_IOIM_SM_HWFAIL = 17, /* IOC h/w failure event */
+ BFA_IOIM_SM_IOTOV = 18, /* ITN offline TOV */
+};
+
+/*
+ * forward declaration of IO state machine
+ */
+static void bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_active(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_abort(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+static void bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim,
+ enum bfa_ioim_event event);
+
+/**
+ * IO is not started (unallocated).
+ */
+static void
+bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_trc_fp(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_START:
+ if (!bfa_itnim_is_online(ioim->itnim)) {
+ if (!bfa_itnim_hold_io(ioim->itnim)) {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe,
+ &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);
+ }
+ break;
+ }
+
+ if (ioim->nsges > BFI_SGE_INLINE) {
+ if (!bfa_ioim_sge_setup(ioim)) {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_sgalloc);
+ return;
+ }
+ }
+
+ if (!bfa_ioim_send_ioreq(ioim)) {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_qfull);
+ break;
+ }
+
+ bfa_sm_set_state(ioim, bfa_ioim_sm_active);
+ break;
+
+ case BFA_IOIM_SM_IOTOV:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
+ __bfa_cb_ioim_pathtov, ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ /**
+ * IO in pending queue can get abort requests. Complete abort
+ * requests immediately.
+ */
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_assert(bfa_q_is_on_q(&ioim->itnim->pending_q, ioim));
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is waiting for SG pages.
+ */
+static void
+bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_SGALLOCED:
+ if (!bfa_ioim_send_ioreq(ioim)) {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_qfull);
+ break;
+ }
+ bfa_sm_set_state(ioim, bfa_ioim_sm_active);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is active.
+ */
+static void
+bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_trc_fp(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_COMP_GOOD:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe,
+ __bfa_cb_ioim_good_comp, ioim);
+ break;
+
+ case BFA_IOIM_SM_COMP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_DONE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ ioim->iosp->abort_explicit = BFA_TRUE;
+ ioim->io_cbfn = __bfa_cb_ioim_abort;
+
+ if (bfa_ioim_send_abort(ioim))
+ bfa_sm_set_state(ioim, bfa_ioim_sm_abort);
+ else {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_abort_qfull);
+ bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+ &ioim->iosp->reqq_wait);
+ }
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ ioim->iosp->abort_explicit = BFA_FALSE;
+ ioim->io_cbfn = __bfa_cb_ioim_failed;
+
+ if (bfa_ioim_send_abort(ioim))
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
+ else {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
+ bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+ &ioim->iosp->reqq_wait);
+ }
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is being aborted, waiting for completion from firmware.
+ */
+static void
+bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_COMP_GOOD:
+ case BFA_IOIM_SM_COMP:
+ case BFA_IOIM_SM_DONE:
+ case BFA_IOIM_SM_FREE:
+ break;
+
+ case BFA_IOIM_SM_ABORT_DONE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT_COMP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_COMP_UTAG:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE);
+ ioim->iosp->abort_explicit = BFA_FALSE;
+
+ if (bfa_ioim_send_abort(ioim))
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
+ else {
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
+ bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+ &ioim->iosp->reqq_wait);
+ }
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is being cleaned up (implicit abort), waiting for completion from
+ * firmware.
+ */
+static void
+bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_COMP_GOOD:
+ case BFA_IOIM_SM_COMP:
+ case BFA_IOIM_SM_DONE:
+ case BFA_IOIM_SM_FREE:
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ /**
+ * IO is already being aborted implicitly
+ */
+ ioim->io_cbfn = __bfa_cb_ioim_abort;
+ break;
+
+ case BFA_IOIM_SM_ABORT_DONE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT_COMP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_COMP_UTAG:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ /**
+ * IO can be in cleanup state already due to TM command. 2nd cleanup
+ * request comes from ITN offline event.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is waiting for room in request CQ
+ */
+static void
+bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_QRESUME:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_active);
+ bfa_ioim_send_ioreq(ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Active IO is being aborted, waiting for room in request CQ.
+ */
+static void
+bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_QRESUME:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_abort);
+ bfa_ioim_send_abort(ioim);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_assert(ioim->iosp->abort_explicit == BFA_TRUE);
+ ioim->iosp->abort_explicit = BFA_FALSE;
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull);
+ break;
+
+ case BFA_IOIM_SM_COMP_GOOD:
+ case BFA_IOIM_SM_COMP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_DONE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort,
+ ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Active IO is being cleaned up, waiting for room in request CQ.
+ */
+static void
+bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_QRESUME:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup);
+ bfa_ioim_send_abort(ioim);
+ break;
+
+ case BFA_IOIM_SM_ABORT:
+ /**
+ * IO is alraedy being cleaned up implicitly
+ */
+ ioim->io_cbfn = __bfa_cb_ioim_abort;
+ break;
+
+ case BFA_IOIM_SM_COMP_GOOD:
+ case BFA_IOIM_SM_COMP:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_DONE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ bfa_reqq_wcancel(&ioim->iosp->reqq_wait);
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed,
+ ioim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO bfa callback is pending.
+ */
+static void
+bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_trc_fp(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_HCB:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_uninit);
+ bfa_ioim_free(ioim);
+ bfa_cb_ioim_resfree(ioim->bfa->bfad);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO bfa callback is pending. IO resource cannot be freed.
+ */
+static void
+bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_HCB:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_resfree);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_resfree_q);
+ break;
+
+ case BFA_IOIM_SM_FREE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_hcb);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IO is completed, waiting resource free from firmware.
+ */
+static void
+bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, event);
+
+ switch (event) {
+ case BFA_IOIM_SM_FREE:
+ bfa_sm_set_state(ioim, bfa_ioim_sm_uninit);
+ bfa_ioim_free(ioim);
+ bfa_cb_ioim_resfree(ioim->bfa->bfad);
+ break;
+
+ case BFA_IOIM_SM_CLEANUP:
+ bfa_ioim_notify_cleanup(ioim);
+ break;
+
+ case BFA_IOIM_SM_HWFAIL:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_ioim_private
+ */
+
+static void
+__bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+ return;
+ }
+
+ bfa_cb_ioim_good_comp(ioim->bfa->bfad, ioim->dio);
+}
+
+static void
+__bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+ struct bfi_ioim_rsp_s *m;
+ u8 *snsinfo = NULL;
+ u8 sns_len = 0;
+ s32 residue = 0;
+
+ if (!complete) {
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+ return;
+ }
+
+ m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg;
+ if (m->io_status == BFI_IOIM_STS_OK) {
+ /**
+ * setup sense information, if present
+ */
+ if (m->scsi_status == SCSI_STATUS_CHECK_CONDITION
+ && m->sns_len) {
+ sns_len = m->sns_len;
+ snsinfo = ioim->iosp->snsinfo;
+ }
+
+ /**
+ * setup residue value correctly for normal completions
+ */
+ if (m->resid_flags == FCP_RESID_UNDER)
+ residue = bfa_os_ntohl(m->residue);
+ if (m->resid_flags == FCP_RESID_OVER) {
+ residue = bfa_os_ntohl(m->residue);
+ residue = -residue;
+ }
+ }
+
+ bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, m->io_status,
+ m->scsi_status, sns_len, snsinfo, residue);
+}
+
+static void
+__bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+ return;
+ }
+
+ bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED,
+ 0, 0, NULL, 0);
+}
+
+static void
+__bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+ return;
+ }
+
+ bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV,
+ 0, 0, NULL, 0);
+}
+
+static void
+__bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB);
+ return;
+ }
+
+ bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio);
+}
+
+static void
+bfa_ioim_sgpg_alloced(void *cbarg)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ ioim->nsgpgs = BFA_SGPG_NPAGE(ioim->nsges);
+ list_splice_tail_init(&ioim->iosp->sgpg_wqe.sgpg_q, &ioim->sgpg_q);
+ bfa_ioim_sgpg_setup(ioim);
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_SGALLOCED);
+}
+
+/**
+ * Send I/O request to firmware.
+ */
+static bfa_boolean_t
+bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim)
+{
+ struct bfa_itnim_s *itnim = ioim->itnim;
+ struct bfi_ioim_req_s *m;
+ static struct fcp_cmnd_s cmnd_z0 = { 0 };
+ struct bfi_sge_s *sge;
+ u32 pgdlen = 0;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(ioim->bfa, itnim->reqq);
+ if (!m) {
+ bfa_reqq_wait(ioim->bfa, ioim->itnim->reqq,
+ &ioim->iosp->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ /**
+ * build i/o request message next
+ */
+ m->io_tag = bfa_os_htons(ioim->iotag);
+ m->rport_hdl = ioim->itnim->rport->fw_handle;
+ m->io_timeout = bfa_cb_ioim_get_timeout(ioim->dio);
+
+ /**
+ * build inline IO SG element here
+ */
+ sge = &m->sges[0];
+ if (ioim->nsges) {
+ sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, 0);
+ pgdlen = bfa_cb_ioim_get_sglen(ioim->dio, 0);
+ sge->sg_len = pgdlen;
+ sge->flags = (ioim->nsges > BFI_SGE_INLINE) ?
+ BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST;
+ bfa_sge_to_be(sge);
+ sge++;
+ }
+
+ if (ioim->nsges > BFI_SGE_INLINE) {
+ sge->sga = ioim->sgpg->sgpg_pa;
+ } else {
+ sge->sga.a32.addr_lo = 0;
+ sge->sga.a32.addr_hi = 0;
+ }
+ sge->sg_len = pgdlen;
+ sge->flags = BFI_SGE_PGDLEN;
+ bfa_sge_to_be(sge);
+
+ /**
+ * set up I/O command parameters
+ */
+ bfa_os_assign(m->cmnd, cmnd_z0);
+ m->cmnd.lun = bfa_cb_ioim_get_lun(ioim->dio);
+ m->cmnd.iodir = bfa_cb_ioim_get_iodir(ioim->dio);
+ bfa_os_assign(m->cmnd.cdb,
+ *(struct scsi_cdb_s *)bfa_cb_ioim_get_cdb(ioim->dio));
+ m->cmnd.fcp_dl = bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio));
+
+ /**
+ * set up I/O message header
+ */
+ switch (m->cmnd.iodir) {
+ case FCP_IODIR_READ:
+ bfi_h2i_set(m->mh, BFI_MC_IOIM_READ, 0, bfa_lpuid(ioim->bfa));
+ bfa_stats(itnim, input_reqs);
+ break;
+ case FCP_IODIR_WRITE:
+ bfi_h2i_set(m->mh, BFI_MC_IOIM_WRITE, 0, bfa_lpuid(ioim->bfa));
+ bfa_stats(itnim, output_reqs);
+ break;
+ case FCP_IODIR_RW:
+ bfa_stats(itnim, input_reqs);
+ bfa_stats(itnim, output_reqs);
+ default:
+ bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa));
+ }
+ if (itnim->seq_rec ||
+ (bfa_cb_ioim_get_size(ioim->dio) & (sizeof(u32) - 1)))
+ bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_lpuid(ioim->bfa));
+
+#ifdef IOIM_ADVANCED
+ m->cmnd.crn = bfa_cb_ioim_get_crn(ioim->dio);
+ m->cmnd.priority = bfa_cb_ioim_get_priority(ioim->dio);
+ m->cmnd.taskattr = bfa_cb_ioim_get_taskattr(ioim->dio);
+
+ /**
+ * Handle large CDB (>16 bytes).
+ */
+ m->cmnd.addl_cdb_len = (bfa_cb_ioim_get_cdblen(ioim->dio) -
+ FCP_CMND_CDB_LEN) / sizeof(u32);
+ if (m->cmnd.addl_cdb_len) {
+ bfa_os_memcpy(&m->cmnd.cdb + 1, (struct scsi_cdb_s *)
+ bfa_cb_ioim_get_cdb(ioim->dio) + 1,
+ m->cmnd.addl_cdb_len * sizeof(u32));
+ fcp_cmnd_fcpdl(&m->cmnd) =
+ bfa_os_htonl(bfa_cb_ioim_get_size(ioim->dio));
+ }
+#endif
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(ioim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+/**
+ * Setup any additional SG pages needed.Inline SG element is setup
+ * at queuing time.
+ */
+static bfa_boolean_t
+bfa_ioim_sge_setup(struct bfa_ioim_s *ioim)
+{
+ u16 nsgpgs;
+
+ bfa_assert(ioim->nsges > BFI_SGE_INLINE);
+
+ /**
+ * allocate SG pages needed
+ */
+ nsgpgs = BFA_SGPG_NPAGE(ioim->nsges);
+ if (!nsgpgs)
+ return BFA_TRUE;
+
+ if (bfa_sgpg_malloc(ioim->bfa, &ioim->sgpg_q, nsgpgs)
+ != BFA_STATUS_OK) {
+ bfa_sgpg_wait(ioim->bfa, &ioim->iosp->sgpg_wqe, nsgpgs);
+ return BFA_FALSE;
+ }
+
+ ioim->nsgpgs = nsgpgs;
+ bfa_ioim_sgpg_setup(ioim);
+
+ return BFA_TRUE;
+}
+
+static void
+bfa_ioim_sgpg_setup(struct bfa_ioim_s *ioim)
+{
+ int sgeid, nsges, i;
+ struct bfi_sge_s *sge;
+ struct bfa_sgpg_s *sgpg;
+ u32 pgcumsz;
+
+ sgeid = BFI_SGE_INLINE;
+ ioim->sgpg = sgpg = bfa_q_first(&ioim->sgpg_q);
+
+ do {
+ sge = sgpg->sgpg->sges;
+ nsges = ioim->nsges - sgeid;
+ if (nsges > BFI_SGPG_DATA_SGES)
+ nsges = BFI_SGPG_DATA_SGES;
+
+ pgcumsz = 0;
+ for (i = 0; i < nsges; i++, sge++, sgeid++) {
+ sge->sga = bfa_cb_ioim_get_sgaddr(ioim->dio, sgeid);
+ sge->sg_len = bfa_cb_ioim_get_sglen(ioim->dio, sgeid);
+ pgcumsz += sge->sg_len;
+
+ /**
+ * set flags
+ */
+ if (i < (nsges - 1))
+ sge->flags = BFI_SGE_DATA;
+ else if (sgeid < (ioim->nsges - 1))
+ sge->flags = BFI_SGE_DATA_CPL;
+ else
+ sge->flags = BFI_SGE_DATA_LAST;
+ }
+
+ sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg);
+
+ /**
+ * set the link element of each page
+ */
+ if (sgeid == ioim->nsges) {
+ sge->flags = BFI_SGE_PGDLEN;
+ sge->sga.a32.addr_lo = 0;
+ sge->sga.a32.addr_hi = 0;
+ } else {
+ sge->flags = BFI_SGE_LINK;
+ sge->sga = sgpg->sgpg_pa;
+ }
+ sge->sg_len = pgcumsz;
+ } while (sgeid < ioim->nsges);
+}
+
+/**
+ * Send I/O abort request to firmware.
+ */
+static bfa_boolean_t
+bfa_ioim_send_abort(struct bfa_ioim_s *ioim)
+{
+ struct bfa_itnim_s *itnim = ioim->itnim;
+ struct bfi_ioim_abort_req_s *m;
+ enum bfi_ioim_h2i msgop;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(ioim->bfa, itnim->reqq);
+ if (!m)
+ return BFA_FALSE;
+
+ /**
+ * build i/o request message next
+ */
+ if (ioim->iosp->abort_explicit)
+ msgop = BFI_IOIM_H2I_IOABORT_REQ;
+ else
+ msgop = BFI_IOIM_H2I_IOCLEANUP_REQ;
+
+ bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_lpuid(ioim->bfa));
+ m->io_tag = bfa_os_htons(ioim->iotag);
+ m->abort_tag = ++ioim->abort_tag;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(ioim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+/**
+ * Call to resume any I/O requests waiting for room in request queue.
+ */
+static void
+bfa_ioim_qresume(void *cbarg)
+{
+ struct bfa_ioim_s *ioim = cbarg;
+
+ bfa_fcpim_stats(ioim->fcpim, qresumes);
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_QRESUME);
+}
+
+
+static void
+bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim)
+{
+ /**
+ * Move IO from itnim queue to fcpim global queue since itnim will be
+ * freed.
+ */
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
+
+ if (!ioim->iosp->tskim) {
+ if (ioim->fcpim->delay_comp && ioim->itnim->iotov_active) {
+ bfa_cb_dequeue(&ioim->hcb_qe);
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->itnim->delay_comp_q);
+ }
+ bfa_itnim_iodone(ioim->itnim);
+ } else
+ bfa_tskim_iodone(ioim->iosp->tskim);
+}
+
+/**
+ * or after the link comes back.
+ */
+void
+bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov)
+{
+ /**
+ * If path tov timer expired, failback with PATHTOV status - these
+ * IO requests are not normally retried by IO stack.
+ *
+ * Otherwise device cameback online and fail it with normal failed
+ * status so that IO stack retries these failed IO requests.
+ */
+ if (iotov)
+ ioim->io_cbfn = __bfa_cb_ioim_pathtov;
+ else
+ ioim->io_cbfn = __bfa_cb_ioim_failed;
+
+ bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim);
+
+ /**
+ * Move IO to fcpim global queue since itnim will be
+ * freed.
+ */
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
+}
+
+
+
+/**
+ * bfa_ioim_friend
+ */
+
+/**
+ * Memory allocation and initialization.
+ */
+void
+bfa_ioim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
+{
+ struct bfa_ioim_s *ioim;
+ struct bfa_ioim_sp_s *iosp;
+ u16 i;
+ u8 *snsinfo;
+ u32 snsbufsz;
+
+ /**
+ * claim memory first
+ */
+ ioim = (struct bfa_ioim_s *) bfa_meminfo_kva(minfo);
+ fcpim->ioim_arr = ioim;
+ bfa_meminfo_kva(minfo) = (u8 *) (ioim + fcpim->num_ioim_reqs);
+
+ iosp = (struct bfa_ioim_sp_s *) bfa_meminfo_kva(minfo);
+ fcpim->ioim_sp_arr = iosp;
+ bfa_meminfo_kva(minfo) = (u8 *) (iosp + fcpim->num_ioim_reqs);
+
+ /**
+ * Claim DMA memory for per IO sense data.
+ */
+ snsbufsz = fcpim->num_ioim_reqs * BFI_IOIM_SNSLEN;
+ fcpim->snsbase.pa = bfa_meminfo_dma_phys(minfo);
+ bfa_meminfo_dma_phys(minfo) += snsbufsz;
+
+ fcpim->snsbase.kva = bfa_meminfo_dma_virt(minfo);
+ bfa_meminfo_dma_virt(minfo) += snsbufsz;
+ snsinfo = fcpim->snsbase.kva;
+ bfa_iocfc_set_snsbase(fcpim->bfa, fcpim->snsbase.pa);
+
+ /**
+ * Initialize ioim free queues
+ */
+ INIT_LIST_HEAD(&fcpim->ioim_free_q);
+ INIT_LIST_HEAD(&fcpim->ioim_resfree_q);
+ INIT_LIST_HEAD(&fcpim->ioim_comp_q);
+
+ for (i = 0; i < fcpim->num_ioim_reqs;
+ i++, ioim++, iosp++, snsinfo += BFI_IOIM_SNSLEN) {
+ /*
+ * initialize IOIM
+ */
+ bfa_os_memset(ioim, 0, sizeof(struct bfa_ioim_s));
+ ioim->iotag = i;
+ ioim->bfa = fcpim->bfa;
+ ioim->fcpim = fcpim;
+ ioim->iosp = iosp;
+ iosp->snsinfo = snsinfo;
+ INIT_LIST_HEAD(&ioim->sgpg_q);
+ bfa_reqq_winit(&ioim->iosp->reqq_wait,
+ bfa_ioim_qresume, ioim);
+ bfa_sgpg_winit(&ioim->iosp->sgpg_wqe,
+ bfa_ioim_sgpg_alloced, ioim);
+ bfa_sm_set_state(ioim, bfa_ioim_sm_uninit);
+
+ list_add_tail(&ioim->qe, &fcpim->ioim_free_q);
+ }
+}
+
+/**
+ * Driver detach time call.
+ */
+void
+bfa_ioim_detach(struct bfa_fcpim_mod_s *fcpim)
+{
+}
+
+void
+bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m;
+ struct bfa_ioim_s *ioim;
+ u16 iotag;
+ enum bfa_ioim_event evt = BFA_IOIM_SM_COMP;
+
+ iotag = bfa_os_ntohs(rsp->io_tag);
+
+ ioim = BFA_IOIM_FROM_TAG(fcpim, iotag);
+ bfa_assert(ioim->iotag == iotag);
+
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_trc(ioim->bfa, rsp->io_status);
+ bfa_trc(ioim->bfa, rsp->reuse_io_tag);
+
+ if (bfa_sm_cmp_state(ioim, bfa_ioim_sm_active))
+ bfa_os_assign(ioim->iosp->comp_rspmsg, *m);
+
+ switch (rsp->io_status) {
+ case BFI_IOIM_STS_OK:
+ bfa_fcpim_stats(fcpim, iocomp_ok);
+ if (rsp->reuse_io_tag == 0)
+ evt = BFA_IOIM_SM_DONE;
+ else
+ evt = BFA_IOIM_SM_COMP;
+ break;
+
+ case BFI_IOIM_STS_TIMEDOUT:
+ case BFI_IOIM_STS_ABORTED:
+ rsp->io_status = BFI_IOIM_STS_ABORTED;
+ bfa_fcpim_stats(fcpim, iocomp_aborted);
+ if (rsp->reuse_io_tag == 0)
+ evt = BFA_IOIM_SM_DONE;
+ else
+ evt = BFA_IOIM_SM_COMP;
+ break;
+
+ case BFI_IOIM_STS_PROTO_ERR:
+ bfa_fcpim_stats(fcpim, iocom_proto_err);
+ bfa_assert(rsp->reuse_io_tag);
+ evt = BFA_IOIM_SM_COMP;
+ break;
+
+ case BFI_IOIM_STS_SQER_NEEDED:
+ bfa_fcpim_stats(fcpim, iocom_sqer_needed);
+ bfa_assert(rsp->reuse_io_tag == 0);
+ evt = BFA_IOIM_SM_SQRETRY;
+ break;
+
+ case BFI_IOIM_STS_RES_FREE:
+ bfa_fcpim_stats(fcpim, iocom_res_free);
+ evt = BFA_IOIM_SM_FREE;
+ break;
+
+ case BFI_IOIM_STS_HOST_ABORTED:
+ bfa_fcpim_stats(fcpim, iocom_hostabrts);
+ if (rsp->abort_tag != ioim->abort_tag) {
+ bfa_trc(ioim->bfa, rsp->abort_tag);
+ bfa_trc(ioim->bfa, ioim->abort_tag);
+ return;
+ }
+
+ if (rsp->reuse_io_tag)
+ evt = BFA_IOIM_SM_ABORT_COMP;
+ else
+ evt = BFA_IOIM_SM_ABORT_DONE;
+ break;
+
+ case BFI_IOIM_STS_UTAG:
+ bfa_fcpim_stats(fcpim, iocom_utags);
+ evt = BFA_IOIM_SM_COMP_UTAG;
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+
+ bfa_sm_send_event(ioim, evt);
+}
+
+void
+bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m;
+ struct bfa_ioim_s *ioim;
+ u16 iotag;
+
+ iotag = bfa_os_ntohs(rsp->io_tag);
+
+ ioim = BFA_IOIM_FROM_TAG(fcpim, iotag);
+ bfa_assert(ioim->iotag == iotag);
+
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD);
+}
+
+/**
+ * Called by itnim to clean up IO while going offline.
+ */
+void
+bfa_ioim_cleanup(struct bfa_ioim_s *ioim)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_fcpim_stats(ioim->fcpim, io_cleanups);
+
+ ioim->iosp->tskim = NULL;
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP);
+}
+
+void
+bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, struct bfa_tskim_s *tskim)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_fcpim_stats(ioim->fcpim, io_tmaborts);
+
+ ioim->iosp->tskim = tskim;
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP);
+}
+
+/**
+ * IOC failure handling.
+ */
+void
+bfa_ioim_iocdisable(struct bfa_ioim_s *ioim)
+{
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_HWFAIL);
+}
+
+/**
+ * IO offline TOV popped. Fail the pending IO.
+ */
+void
+bfa_ioim_tov(struct bfa_ioim_s *ioim)
+{
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_IOTOV);
+}
+
+
+
+/**
+ * bfa_ioim_api
+ */
+
+/**
+ * Allocate IOIM resource for initiator mode I/O request.
+ */
+struct bfa_ioim_s *
+bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio,
+ struct bfa_itnim_s *itnim, u16 nsges)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfa_ioim_s *ioim;
+
+ /**
+ * alocate IOIM resource
+ */
+ bfa_q_deq(&fcpim->ioim_free_q, &ioim);
+ if (!ioim) {
+ bfa_fcpim_stats(fcpim, no_iotags);
+ return NULL;
+ }
+
+ ioim->dio = dio;
+ ioim->itnim = itnim;
+ ioim->nsges = nsges;
+ ioim->nsgpgs = 0;
+
+ bfa_stats(fcpim, total_ios);
+ bfa_stats(itnim, ios);
+ fcpim->ios_active++;
+
+ list_add_tail(&ioim->qe, &itnim->io_q);
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+
+ return ioim;
+}
+
+void
+bfa_ioim_free(struct bfa_ioim_s *ioim)
+{
+ struct bfa_fcpim_mod_s *fcpim = ioim->fcpim;
+
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_assert_fp(bfa_sm_cmp_state(ioim, bfa_ioim_sm_uninit));
+
+ bfa_assert_fp(list_empty(&ioim->sgpg_q)
+ || (ioim->nsges > BFI_SGE_INLINE));
+
+ if (ioim->nsgpgs > 0)
+ bfa_sgpg_mfree(ioim->bfa, &ioim->sgpg_q, ioim->nsgpgs);
+
+ bfa_stats(ioim->itnim, io_comps);
+ fcpim->ios_active--;
+
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &fcpim->ioim_free_q);
+}
+
+void
+bfa_ioim_start(struct bfa_ioim_s *ioim)
+{
+ bfa_trc_fp(ioim->bfa, ioim->iotag);
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_START);
+}
+
+/**
+ * Driver I/O abort request.
+ */
+void
+bfa_ioim_abort(struct bfa_ioim_s *ioim)
+{
+ bfa_trc(ioim->bfa, ioim->iotag);
+ bfa_fcpim_stats(ioim->fcpim, io_aborts);
+ bfa_sm_send_event(ioim, BFA_IOIM_SM_ABORT);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_itnim.c b/drivers/scsi/bfa/bfa_itnim.c
new file mode 100644
index 000000000000..eabf7d38bd09
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_itnim.c
@@ -0,0 +1,1088 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <bfa_fcpim.h>
+#include "bfa_fcpim_priv.h"
+
+BFA_TRC_FILE(HAL, ITNIM);
+
+#define BFA_ITNIM_FROM_TAG(_fcpim, _tag) \
+ ((_fcpim)->itnim_arr + ((_tag) & ((_fcpim)->num_itnims - 1)))
+
+#define bfa_fcpim_additn(__itnim) \
+ list_add_tail(&(__itnim)->qe, &(__itnim)->fcpim->itnim_q)
+#define bfa_fcpim_delitn(__itnim) do { \
+ bfa_assert(bfa_q_is_on_q(&(__itnim)->fcpim->itnim_q, __itnim)); \
+ list_del(&(__itnim)->qe); \
+ bfa_assert(list_empty(&(__itnim)->io_q)); \
+ bfa_assert(list_empty(&(__itnim)->io_cleanup_q)); \
+ bfa_assert(list_empty(&(__itnim)->pending_q)); \
+} while (0)
+
+#define bfa_itnim_online_cb(__itnim) do { \
+ if ((__itnim)->bfa->fcs) \
+ bfa_cb_itnim_online((__itnim)->ditn); \
+ else { \
+ bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \
+ __bfa_cb_itnim_online, (__itnim)); \
+ } \
+} while (0)
+
+#define bfa_itnim_offline_cb(__itnim) do { \
+ if ((__itnim)->bfa->fcs) \
+ bfa_cb_itnim_offline((__itnim)->ditn); \
+ else { \
+ bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \
+ __bfa_cb_itnim_offline, (__itnim)); \
+ } \
+} while (0)
+
+#define bfa_itnim_sler_cb(__itnim) do { \
+ if ((__itnim)->bfa->fcs) \
+ bfa_cb_itnim_sler((__itnim)->ditn); \
+ else { \
+ bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \
+ __bfa_cb_itnim_sler, (__itnim)); \
+ } \
+} while (0)
+
+/*
+ * forward declarations
+ */
+static void bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim);
+static bfa_boolean_t bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim);
+static bfa_boolean_t bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim);
+static void bfa_itnim_cleanp_comp(void *itnim_cbarg);
+static void bfa_itnim_cleanup(struct bfa_itnim_s *itnim);
+static void __bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete);
+static void bfa_itnim_iotov_online(struct bfa_itnim_s *itnim);
+static void bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim);
+static void bfa_itnim_iotov(void *itnim_arg);
+static void bfa_itnim_iotov_start(struct bfa_itnim_s *itnim);
+static void bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim);
+static void bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim);
+
+/**
+ * bfa_itnim_sm BFA itnim state machine
+ */
+
+
+enum bfa_itnim_event {
+ BFA_ITNIM_SM_CREATE = 1, /* itnim is created */
+ BFA_ITNIM_SM_ONLINE = 2, /* itnim is online */
+ BFA_ITNIM_SM_OFFLINE = 3, /* itnim is offline */
+ BFA_ITNIM_SM_FWRSP = 4, /* firmware response */
+ BFA_ITNIM_SM_DELETE = 5, /* deleting an existing itnim */
+ BFA_ITNIM_SM_CLEANUP = 6, /* IO cleanup completion */
+ BFA_ITNIM_SM_SLER = 7, /* second level error recovery */
+ BFA_ITNIM_SM_HWFAIL = 8, /* IOC h/w failure event */
+ BFA_ITNIM_SM_QRESUME = 9, /* queue space available */
+};
+
+static void bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_created(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_online(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_sler(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_offline(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+static void bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event);
+
+/**
+ * Beginning/unallocated state - no events expected.
+ */
+static void
+bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_CREATE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_created);
+ itnim->is_online = BFA_FALSE;
+ bfa_fcpim_additn(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Beginning state, only online event expected.
+ */
+static void
+bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_ONLINE:
+ if (bfa_itnim_send_fwcreate(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Waiting for itnim create response from firmware.
+ */
+static void
+bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_FWRSP:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_online);
+ itnim->is_online = BFA_TRUE;
+ bfa_itnim_iotov_online(itnim);
+ bfa_itnim_online_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_delete_pending);
+ break;
+
+ case BFA_ITNIM_SM_OFFLINE:
+ if (bfa_itnim_send_fwdelete(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_QRESUME:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate);
+ bfa_itnim_send_fwcreate(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_reqq_wcancel(&itnim->reqq_wait);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ case BFA_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_offline);
+ bfa_reqq_wcancel(&itnim->reqq_wait);
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_reqq_wcancel(&itnim->reqq_wait);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Waiting for itnim create response from firmware, a delete is pending.
+ */
+static void
+bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_FWRSP:
+ if (bfa_itnim_send_fwdelete(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Online state - normal parking state.
+ */
+static void
+bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline);
+ itnim->is_online = BFA_FALSE;
+ bfa_itnim_iotov_start(itnim);
+ bfa_itnim_cleanup(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete);
+ itnim->is_online = BFA_FALSE;
+ bfa_itnim_cleanup(itnim);
+ break;
+
+ case BFA_ITNIM_SM_SLER:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_sler);
+ itnim->is_online = BFA_FALSE;
+ bfa_itnim_iotov_start(itnim);
+ bfa_itnim_sler_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ itnim->is_online = BFA_FALSE;
+ bfa_itnim_iotov_start(itnim);
+ bfa_itnim_iocdisable_cleanup(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Second level error recovery need.
+ */
+static void
+bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline);
+ bfa_itnim_cleanup(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete);
+ bfa_itnim_cleanup(itnim);
+ bfa_itnim_iotov_delete(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_itnim_iocdisable_cleanup(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Going offline. Waiting for active IO cleanup.
+ */
+static void
+bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_CLEANUP:
+ if (bfa_itnim_send_fwdelete(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete);
+ bfa_itnim_iotov_delete(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_itnim_iocdisable_cleanup(itnim);
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_SLER:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Deleting itnim. Waiting for active IO cleanup.
+ */
+static void
+bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_CLEANUP:
+ if (bfa_itnim_send_fwdelete(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_itnim_iocdisable_cleanup(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport offline. Fimrware itnim is being deleted - awaiting f/w response.
+ */
+static void
+bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_FWRSP:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_offline);
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_QRESUME:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete);
+ bfa_itnim_send_fwdelete(itnim);
+ break;
+
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ bfa_reqq_wcancel(&itnim->reqq_wait);
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Offline state.
+ */
+static void
+bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_itnim_iotov_delete(itnim);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ case BFA_ITNIM_SM_ONLINE:
+ if (bfa_itnim_send_fwcreate(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IOC h/w failed state.
+ */
+static void
+bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_itnim_iotov_delete(itnim);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ case BFA_ITNIM_SM_OFFLINE:
+ bfa_itnim_offline_cb(itnim);
+ break;
+
+ case BFA_ITNIM_SM_ONLINE:
+ if (bfa_itnim_send_fwcreate(itnim))
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate);
+ else
+ bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Itnim is deleted, waiting for firmware response to delete.
+ */
+static void
+bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_FWRSP:
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim,
+ enum bfa_itnim_event event)
+{
+ bfa_trc(itnim->bfa, itnim->rport->rport_tag);
+ bfa_trc(itnim->bfa, event);
+
+ switch (event) {
+ case BFA_ITNIM_SM_QRESUME:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_deleting);
+ bfa_itnim_send_fwdelete(itnim);
+ break;
+
+ case BFA_ITNIM_SM_HWFAIL:
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ bfa_reqq_wcancel(&itnim->reqq_wait);
+ bfa_fcpim_delitn(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_itnim_private
+ */
+
+/**
+ * Initiate cleanup of all IOs on an IOC failure.
+ */
+static void
+bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim)
+{
+ struct bfa_tskim_s *tskim;
+ struct bfa_ioim_s *ioim;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &itnim->tsk_q) {
+ tskim = (struct bfa_tskim_s *) qe;
+ bfa_tskim_iocdisable(tskim);
+ }
+
+ list_for_each_safe(qe, qen, &itnim->io_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ bfa_ioim_iocdisable(ioim);
+ }
+
+ /**
+ * For IO request in pending queue, we pretend an early timeout.
+ */
+ list_for_each_safe(qe, qen, &itnim->pending_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ bfa_ioim_tov(ioim);
+ }
+
+ list_for_each_safe(qe, qen, &itnim->io_cleanup_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ bfa_ioim_iocdisable(ioim);
+ }
+}
+
+/**
+ * IO cleanup completion
+ */
+static void
+bfa_itnim_cleanp_comp(void *itnim_cbarg)
+{
+ struct bfa_itnim_s *itnim = itnim_cbarg;
+
+ bfa_stats(itnim, cleanup_comps);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_CLEANUP);
+}
+
+/**
+ * Initiate cleanup of all IOs.
+ */
+static void
+bfa_itnim_cleanup(struct bfa_itnim_s *itnim)
+{
+ struct bfa_ioim_s *ioim;
+ struct bfa_tskim_s *tskim;
+ struct list_head *qe, *qen;
+
+ bfa_wc_init(&itnim->wc, bfa_itnim_cleanp_comp, itnim);
+
+ list_for_each_safe(qe, qen, &itnim->io_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+
+ /**
+ * Move IO to a cleanup queue from active queue so that a later
+ * TM will not pickup this IO.
+ */
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &itnim->io_cleanup_q);
+
+ bfa_wc_up(&itnim->wc);
+ bfa_ioim_cleanup(ioim);
+ }
+
+ list_for_each_safe(qe, qen, &itnim->tsk_q) {
+ tskim = (struct bfa_tskim_s *) qe;
+ bfa_wc_up(&itnim->wc);
+ bfa_tskim_cleanup(tskim);
+ }
+
+ bfa_wc_wait(&itnim->wc);
+}
+
+static void
+__bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_itnim_s *itnim = cbarg;
+
+ if (complete)
+ bfa_cb_itnim_online(itnim->ditn);
+}
+
+static void
+__bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_itnim_s *itnim = cbarg;
+
+ if (complete)
+ bfa_cb_itnim_offline(itnim->ditn);
+}
+
+static void
+__bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_itnim_s *itnim = cbarg;
+
+ if (complete)
+ bfa_cb_itnim_sler(itnim->ditn);
+}
+
+/**
+ * Call to resume any I/O requests waiting for room in request queue.
+ */
+static void
+bfa_itnim_qresume(void *cbarg)
+{
+ struct bfa_itnim_s *itnim = cbarg;
+
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_QRESUME);
+}
+
+
+
+
+/**
+ * bfa_itnim_public
+ */
+
+void
+bfa_itnim_iodone(struct bfa_itnim_s *itnim)
+{
+ bfa_wc_down(&itnim->wc);
+}
+
+void
+bfa_itnim_tskdone(struct bfa_itnim_s *itnim)
+{
+ bfa_wc_down(&itnim->wc);
+}
+
+void
+bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len)
+{
+ /**
+ * ITN memory
+ */
+ *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itnim_s);
+}
+
+void
+bfa_itnim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
+{
+ struct bfa_s *bfa = fcpim->bfa;
+ struct bfa_itnim_s *itnim;
+ int i;
+
+ INIT_LIST_HEAD(&fcpim->itnim_q);
+
+ itnim = (struct bfa_itnim_s *) bfa_meminfo_kva(minfo);
+ fcpim->itnim_arr = itnim;
+
+ for (i = 0; i < fcpim->num_itnims; i++, itnim++) {
+ bfa_os_memset(itnim, 0, sizeof(struct bfa_itnim_s));
+ itnim->bfa = bfa;
+ itnim->fcpim = fcpim;
+ itnim->reqq = BFA_REQQ_QOS_LO;
+ itnim->rport = BFA_RPORT_FROM_TAG(bfa, i);
+ itnim->iotov_active = BFA_FALSE;
+ bfa_reqq_winit(&itnim->reqq_wait, bfa_itnim_qresume, itnim);
+
+ INIT_LIST_HEAD(&itnim->io_q);
+ INIT_LIST_HEAD(&itnim->io_cleanup_q);
+ INIT_LIST_HEAD(&itnim->pending_q);
+ INIT_LIST_HEAD(&itnim->tsk_q);
+ INIT_LIST_HEAD(&itnim->delay_comp_q);
+ bfa_sm_set_state(itnim, bfa_itnim_sm_uninit);
+ }
+
+ bfa_meminfo_kva(minfo) = (u8 *) itnim;
+}
+
+void
+bfa_itnim_iocdisable(struct bfa_itnim_s *itnim)
+{
+ bfa_stats(itnim, ioc_disabled);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_HWFAIL);
+}
+
+static bfa_boolean_t
+bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim)
+{
+ struct bfi_itnim_create_req_s *m;
+
+ itnim->msg_no++;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(itnim->bfa, itnim->reqq);
+ if (!m) {
+ bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_CREATE_REQ,
+ bfa_lpuid(itnim->bfa));
+ m->fw_handle = itnim->rport->fw_handle;
+ m->class = FC_CLASS_3;
+ m->seq_rec = itnim->seq_rec;
+ m->msg_no = itnim->msg_no;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(itnim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+static bfa_boolean_t
+bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim)
+{
+ struct bfi_itnim_delete_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(itnim->bfa, itnim->reqq);
+ if (!m) {
+ bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_ITNIM, BFI_ITNIM_H2I_DELETE_REQ,
+ bfa_lpuid(itnim->bfa));
+ m->fw_handle = itnim->rport->fw_handle;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(itnim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+/**
+ * Cleanup all pending failed inflight requests.
+ */
+static void
+bfa_itnim_delayed_comp(struct bfa_itnim_s *itnim, bfa_boolean_t iotov)
+{
+ struct bfa_ioim_s *ioim;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &itnim->delay_comp_q) {
+ ioim = (struct bfa_ioim_s *)qe;
+ bfa_ioim_delayed_comp(ioim, iotov);
+ }
+}
+
+/**
+ * Start all pending IO requests.
+ */
+static void
+bfa_itnim_iotov_online(struct bfa_itnim_s *itnim)
+{
+ struct bfa_ioim_s *ioim;
+
+ bfa_itnim_iotov_stop(itnim);
+
+ /**
+ * Abort all inflight IO requests in the queue
+ */
+ bfa_itnim_delayed_comp(itnim, BFA_FALSE);
+
+ /**
+ * Start all pending IO requests.
+ */
+ while (!list_empty(&itnim->pending_q)) {
+ bfa_q_deq(&itnim->pending_q, &ioim);
+ list_add_tail(&ioim->qe, &itnim->io_q);
+ bfa_ioim_start(ioim);
+ }
+}
+
+/**
+ * Fail all pending IO requests
+ */
+static void
+bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim)
+{
+ struct bfa_ioim_s *ioim;
+
+ /**
+ * Fail all inflight IO requests in the queue
+ */
+ bfa_itnim_delayed_comp(itnim, BFA_TRUE);
+
+ /**
+ * Fail any pending IO requests.
+ */
+ while (!list_empty(&itnim->pending_q)) {
+ bfa_q_deq(&itnim->pending_q, &ioim);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
+ bfa_ioim_tov(ioim);
+ }
+}
+
+/**
+ * IO TOV timer callback. Fail any pending IO requests.
+ */
+static void
+bfa_itnim_iotov(void *itnim_arg)
+{
+ struct bfa_itnim_s *itnim = itnim_arg;
+
+ itnim->iotov_active = BFA_FALSE;
+
+ bfa_cb_itnim_tov_begin(itnim->ditn);
+ bfa_itnim_iotov_cleanup(itnim);
+ bfa_cb_itnim_tov(itnim->ditn);
+}
+
+/**
+ * Start IO TOV timer for failing back pending IO requests in offline state.
+ */
+static void
+bfa_itnim_iotov_start(struct bfa_itnim_s *itnim)
+{
+ if (itnim->fcpim->path_tov > 0) {
+
+ itnim->iotov_active = BFA_TRUE;
+ bfa_assert(bfa_itnim_hold_io(itnim));
+ bfa_timer_start(itnim->bfa, &itnim->timer,
+ bfa_itnim_iotov, itnim, itnim->fcpim->path_tov);
+ }
+}
+
+/**
+ * Stop IO TOV timer.
+ */
+static void
+bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim)
+{
+ if (itnim->iotov_active) {
+ itnim->iotov_active = BFA_FALSE;
+ bfa_timer_stop(&itnim->timer);
+ }
+}
+
+/**
+ * Stop IO TOV timer.
+ */
+static void
+bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim)
+{
+ bfa_boolean_t pathtov_active = BFA_FALSE;
+
+ if (itnim->iotov_active)
+ pathtov_active = BFA_TRUE;
+
+ bfa_itnim_iotov_stop(itnim);
+ if (pathtov_active)
+ bfa_cb_itnim_tov_begin(itnim->ditn);
+ bfa_itnim_iotov_cleanup(itnim);
+ if (pathtov_active)
+ bfa_cb_itnim_tov(itnim->ditn);
+}
+
+
+
+/**
+ * bfa_itnim_public
+ */
+
+/**
+ * Itnim interrupt processing.
+ */
+void
+bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ union bfi_itnim_i2h_msg_u msg;
+ struct bfa_itnim_s *itnim;
+
+ bfa_trc(bfa, m->mhdr.msg_id);
+
+ msg.msg = m;
+
+ switch (m->mhdr.msg_id) {
+ case BFI_ITNIM_I2H_CREATE_RSP:
+ itnim = BFA_ITNIM_FROM_TAG(fcpim,
+ msg.create_rsp->bfa_handle);
+ bfa_assert(msg.create_rsp->status == BFA_STATUS_OK);
+ bfa_stats(itnim, create_comps);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP);
+ break;
+
+ case BFI_ITNIM_I2H_DELETE_RSP:
+ itnim = BFA_ITNIM_FROM_TAG(fcpim,
+ msg.delete_rsp->bfa_handle);
+ bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK);
+ bfa_stats(itnim, delete_comps);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP);
+ break;
+
+ case BFI_ITNIM_I2H_SLER_EVENT:
+ itnim = BFA_ITNIM_FROM_TAG(fcpim,
+ msg.sler_event->bfa_handle);
+ bfa_stats(itnim, sler_events);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_SLER);
+ break;
+
+ default:
+ bfa_trc(bfa, m->mhdr.msg_id);
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_itnim_api
+ */
+
+struct bfa_itnim_s *
+bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfa_itnim_s *itnim;
+
+ itnim = BFA_ITNIM_FROM_TAG(fcpim, rport->rport_tag);
+ bfa_assert(itnim->rport == rport);
+
+ itnim->ditn = ditn;
+
+ bfa_stats(itnim, creates);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_CREATE);
+
+ return itnim;
+}
+
+void
+bfa_itnim_delete(struct bfa_itnim_s *itnim)
+{
+ bfa_stats(itnim, deletes);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_DELETE);
+}
+
+void
+bfa_itnim_online(struct bfa_itnim_s *itnim, bfa_boolean_t seq_rec)
+{
+ itnim->seq_rec = seq_rec;
+ bfa_stats(itnim, onlines);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_ONLINE);
+}
+
+void
+bfa_itnim_offline(struct bfa_itnim_s *itnim)
+{
+ bfa_stats(itnim, offlines);
+ bfa_sm_send_event(itnim, BFA_ITNIM_SM_OFFLINE);
+}
+
+/**
+ * Return true if itnim is considered offline for holding off IO request.
+ * IO is not held if itnim is being deleted.
+ */
+bfa_boolean_t
+bfa_itnim_hold_io(struct bfa_itnim_s *itnim)
+{
+ 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) ||
+ bfa_sm_cmp_state(itnim, bfa_itnim_sm_cleanup_offline) ||
+ 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
+bfa_itnim_get_stats(struct bfa_itnim_s *itnim,
+ struct bfa_itnim_hal_stats_s *stats)
+{
+ *stats = itnim->stats;
+}
+
+void
+bfa_itnim_clear_stats(struct bfa_itnim_s *itnim)
+{
+ bfa_os_memset(&itnim->stats, 0, sizeof(itnim->stats));
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_log.c b/drivers/scsi/bfa/bfa_log.c
new file mode 100644
index 000000000000..e7514016c9c6
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_log.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_log.c BFA log library
+ */
+
+#include <bfa_os_inc.h>
+#include <cs/bfa_log.h>
+
+/*
+ * global log info structure
+ */
+struct bfa_log_info_s {
+ u32 start_idx; /* start index for a module */
+ u32 total_count; /* total count for a module */
+ enum bfa_log_severity level; /* global log level */
+ bfa_log_cb_t cbfn; /* callback function */
+};
+
+static struct bfa_log_info_s bfa_log_info[BFA_LOG_MODULE_ID_MAX + 1];
+static u32 bfa_log_msg_total_count;
+static int bfa_log_initialized;
+
+static char *bfa_log_severity[] =
+ { "[none]", "[critical]", "[error]", "[warn]", "[info]", "" };
+
+/**
+ * BFA log library initialization
+ *
+ * The log library initialization includes the following,
+ * - set log instance name and callback function
+ * - read the message array generated from xml files
+ * - calculate start index for each module
+ * - calculate message count for each module
+ * - perform error checking
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] instance_name - instance name
+ * @param[in] cbfn - callback function
+ *
+ * It return 0 on success, or -1 on failure
+ */
+int
+bfa_log_init(struct bfa_log_mod_s *log_mod, char *instance_name,
+ bfa_log_cb_t cbfn)
+{
+ struct bfa_log_msgdef_s *msg;
+ u32 pre_mod_id = 0;
+ u32 cur_mod_id = 0;
+ u32 i, pre_idx, idx, msg_id;
+
+ /*
+ * set instance name
+ */
+ if (log_mod) {
+ strncpy(log_mod->instance_info, instance_name,
+ sizeof(log_mod->instance_info));
+ log_mod->cbfn = cbfn;
+ for (i = 0; i <= BFA_LOG_MODULE_ID_MAX; i++)
+ log_mod->log_level[i] = BFA_LOG_WARNING;
+ }
+
+ if (bfa_log_initialized)
+ return 0;
+
+ for (i = 0; i <= BFA_LOG_MODULE_ID_MAX; i++) {
+ bfa_log_info[i].start_idx = 0;
+ bfa_log_info[i].total_count = 0;
+ bfa_log_info[i].level = BFA_LOG_WARNING;
+ bfa_log_info[i].cbfn = cbfn;
+ }
+
+ pre_idx = 0;
+ idx = 0;
+ msg = bfa_log_msg_array;
+ msg_id = BFA_LOG_GET_MSG_ID(msg);
+ pre_mod_id = BFA_LOG_GET_MOD_ID(msg_id);
+ while (msg_id != 0) {
+ cur_mod_id = BFA_LOG_GET_MOD_ID(msg_id);
+
+ if (cur_mod_id > BFA_LOG_MODULE_ID_MAX) {
+ cbfn(log_mod, msg_id,
+ "%s%s log: module id %u out of range\n",
+ BFA_LOG_CAT_NAME,
+ bfa_log_severity[BFA_LOG_ERROR],
+ cur_mod_id);
+ return -1;
+ }
+
+ if (pre_mod_id > BFA_LOG_MODULE_ID_MAX) {
+ cbfn(log_mod, msg_id,
+ "%s%s log: module id %u out of range\n",
+ BFA_LOG_CAT_NAME,
+ bfa_log_severity[BFA_LOG_ERROR],
+ pre_mod_id);
+ return -1;
+ }
+
+ if (cur_mod_id != pre_mod_id) {
+ bfa_log_info[pre_mod_id].start_idx = pre_idx;
+ bfa_log_info[pre_mod_id].total_count = idx - pre_idx;
+ pre_mod_id = cur_mod_id;
+ pre_idx = idx;
+ }
+
+ idx++;
+ msg++;
+ msg_id = BFA_LOG_GET_MSG_ID(msg);
+ }
+
+ bfa_log_info[cur_mod_id].start_idx = pre_idx;
+ bfa_log_info[cur_mod_id].total_count = idx - pre_idx;
+ bfa_log_msg_total_count = idx;
+
+ cbfn(log_mod, msg_id, "%s%s log: init OK, msg total count %u\n",
+ BFA_LOG_CAT_NAME,
+ bfa_log_severity[BFA_LOG_INFO], bfa_log_msg_total_count);
+
+ bfa_log_initialized = 1;
+
+ return 0;
+}
+
+/**
+ * BFA log set log level for a module
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] mod_id - module id
+ * @param[in] log_level - log severity level
+ *
+ * It return BFA_STATUS_OK on success, or > 0 on failure
+ */
+bfa_status_t
+bfa_log_set_level(struct bfa_log_mod_s *log_mod, int mod_id,
+ enum bfa_log_severity log_level)
+{
+ if (mod_id <= BFA_LOG_UNUSED_ID || mod_id > BFA_LOG_MODULE_ID_MAX)
+ return BFA_STATUS_EINVAL;
+
+ if (log_level <= BFA_LOG_INVALID || log_level > BFA_LOG_LEVEL_MAX)
+ return BFA_STATUS_EINVAL;
+
+ if (log_mod)
+ log_mod->log_level[mod_id] = log_level;
+ else
+ bfa_log_info[mod_id].level = log_level;
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * BFA log set log level for all modules
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] log_level - log severity level
+ *
+ * It return BFA_STATUS_OK on success, or > 0 on failure
+ */
+bfa_status_t
+bfa_log_set_level_all(struct bfa_log_mod_s *log_mod,
+ enum bfa_log_severity log_level)
+{
+ int mod_id = BFA_LOG_UNUSED_ID + 1;
+
+ if (log_level <= BFA_LOG_INVALID || log_level > BFA_LOG_LEVEL_MAX)
+ return BFA_STATUS_EINVAL;
+
+ if (log_mod) {
+ for (; mod_id <= BFA_LOG_MODULE_ID_MAX; mod_id++)
+ log_mod->log_level[mod_id] = log_level;
+ } else {
+ for (; mod_id <= BFA_LOG_MODULE_ID_MAX; mod_id++)
+ bfa_log_info[mod_id].level = log_level;
+ }
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * BFA log set log level for all aen sub-modules
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] log_level - log severity level
+ *
+ * It return BFA_STATUS_OK on success, or > 0 on failure
+ */
+bfa_status_t
+bfa_log_set_level_aen(struct bfa_log_mod_s *log_mod,
+ enum bfa_log_severity log_level)
+{
+ int mod_id = BFA_LOG_AEN_MIN + 1;
+
+ if (log_mod) {
+ for (; mod_id <= BFA_LOG_AEN_MAX; mod_id++)
+ log_mod->log_level[mod_id] = log_level;
+ } else {
+ for (; mod_id <= BFA_LOG_AEN_MAX; mod_id++)
+ bfa_log_info[mod_id].level = log_level;
+ }
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * BFA log get log level for a module
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] mod_id - module id
+ *
+ * It returns log level or -1 on error
+ */
+enum bfa_log_severity
+bfa_log_get_level(struct bfa_log_mod_s *log_mod, int mod_id)
+{
+ if (mod_id <= BFA_LOG_UNUSED_ID || mod_id > BFA_LOG_MODULE_ID_MAX)
+ return BFA_LOG_INVALID;
+
+ if (log_mod)
+ return log_mod->log_level[mod_id];
+ else
+ return bfa_log_info[mod_id].level;
+}
+
+enum bfa_log_severity
+bfa_log_get_msg_level(struct bfa_log_mod_s *log_mod, u32 msg_id)
+{
+ struct bfa_log_msgdef_s *msg;
+ u32 mod = BFA_LOG_GET_MOD_ID(msg_id);
+ u32 idx = BFA_LOG_GET_MSG_IDX(msg_id) - 1;
+
+ if (!bfa_log_initialized)
+ return BFA_LOG_INVALID;
+
+ if (mod > BFA_LOG_MODULE_ID_MAX)
+ return BFA_LOG_INVALID;
+
+ if (idx >= bfa_log_info[mod].total_count) {
+ bfa_log_info[mod].cbfn(log_mod, msg_id,
+ "%s%s log: inconsistent idx %u vs. total count %u\n",
+ BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], idx,
+ bfa_log_info[mod].total_count);
+ return BFA_LOG_INVALID;
+ }
+
+ msg = bfa_log_msg_array + bfa_log_info[mod].start_idx + idx;
+ if (msg_id != BFA_LOG_GET_MSG_ID(msg)) {
+ bfa_log_info[mod].cbfn(log_mod, msg_id,
+ "%s%s log: inconsistent msg id %u array msg id %u\n",
+ BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR],
+ msg_id, BFA_LOG_GET_MSG_ID(msg));
+ return BFA_LOG_INVALID;
+ }
+
+ return BFA_LOG_GET_SEVERITY(msg);
+}
+
+/**
+ * BFA log message handling
+ *
+ * BFA log message handling finds the message based on message id and prints
+ * out the message based on its format and arguments. It also does prefix
+ * the severity etc.
+ *
+ * @param[in] log_mod - log module info
+ * @param[in] msg_id - message id
+ * @param[in] ... - message arguments
+ *
+ * It return 0 on success, or -1 on errors
+ */
+int
+bfa_log(struct bfa_log_mod_s *log_mod, u32 msg_id, ...)
+{
+ va_list ap;
+ char buf[256];
+ struct bfa_log_msgdef_s *msg;
+ int log_level;
+ u32 mod = BFA_LOG_GET_MOD_ID(msg_id);
+ u32 idx = BFA_LOG_GET_MSG_IDX(msg_id) - 1;
+
+ if (!bfa_log_initialized)
+ return -1;
+
+ if (mod > BFA_LOG_MODULE_ID_MAX)
+ return -1;
+
+ if (idx >= bfa_log_info[mod].total_count) {
+ bfa_log_info[mod].
+ cbfn
+ (log_mod, msg_id,
+ "%s%s log: inconsistent idx %u vs. total count %u\n",
+ BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR], idx,
+ bfa_log_info[mod].total_count);
+ return -1;
+ }
+
+ msg = bfa_log_msg_array + bfa_log_info[mod].start_idx + idx;
+ if (msg_id != BFA_LOG_GET_MSG_ID(msg)) {
+ bfa_log_info[mod].
+ cbfn
+ (log_mod, msg_id,
+ "%s%s log: inconsistent msg id %u array msg id %u\n",
+ BFA_LOG_CAT_NAME, bfa_log_severity[BFA_LOG_ERROR],
+ msg_id, BFA_LOG_GET_MSG_ID(msg));
+ return -1;
+ }
+
+ log_level = log_mod ? log_mod->log_level[mod] : bfa_log_info[mod].level;
+ if ((BFA_LOG_GET_SEVERITY(msg) > log_level) &&
+ (msg->attributes != BFA_LOG_ATTR_NONE))
+ return 0;
+
+ va_start(ap, msg_id);
+ bfa_os_vsprintf(buf, BFA_LOG_GET_MSG_FMT_STRING(msg), ap);
+ va_end(ap);
+
+ if (log_mod)
+ log_mod->cbfn(log_mod, msg_id, "%s[%s]%s%s %s: %s\n",
+ BFA_LOG_CAT_NAME, log_mod->instance_info,
+ bfa_log_severity[BFA_LOG_GET_SEVERITY(msg)],
+ (msg->attributes & BFA_LOG_ATTR_AUDIT)
+ ? " (audit) " : "", msg->msg_value, buf);
+ else
+ bfa_log_info[mod].cbfn(log_mod, msg_id, "%s%s%s %s: %s\n",
+ BFA_LOG_CAT_NAME,
+ bfa_log_severity[BFA_LOG_GET_SEVERITY(msg)],
+ (msg->attributes & BFA_LOG_ATTR_AUDIT) ?
+ " (audit) " : "", msg->msg_value, buf);
+
+ return 0;
+}
+
diff --git a/drivers/scsi/bfa/bfa_log_module.c b/drivers/scsi/bfa/bfa_log_module.c
new file mode 100644
index 000000000000..5c154d341d69
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_log_module.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <cs/bfa_log.h>
+#include <aen/bfa_aen_adapter.h>
+#include <aen/bfa_aen_audit.h>
+#include <aen/bfa_aen_ethport.h>
+#include <aen/bfa_aen_ioc.h>
+#include <aen/bfa_aen_itnim.h>
+#include <aen/bfa_aen_lport.h>
+#include <aen/bfa_aen_port.h>
+#include <aen/bfa_aen_rport.h>
+#include <log/bfa_log_fcs.h>
+#include <log/bfa_log_hal.h>
+#include <log/bfa_log_linux.h>
+#include <log/bfa_log_wdrv.h>
+
+struct bfa_log_msgdef_s bfa_log_msg_array[] = {
+
+
+/* messages define for BFA_AEN_CAT_ADAPTER Module */
+{BFA_AEN_ADAPTER_ADD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ADAPTER_ADD",
+ "New adapter found: SN = %s, base port WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_ADAPTER_REMOVE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_ADAPTER_REMOVE",
+ "Adapter removed: SN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+
+
+
+/* messages define for BFA_AEN_CAT_AUDIT Module */
+{BFA_AEN_AUDIT_AUTH_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "BFA_AEN_AUDIT_AUTH_ENABLE",
+ "Authentication enabled for base port: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_AUDIT_AUTH_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "BFA_AEN_AUDIT_AUTH_DISABLE",
+ "Authentication disabled for base port: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+
+
+
+/* messages define for BFA_AEN_CAT_ETHPORT Module */
+{BFA_AEN_ETHPORT_LINKUP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ETHPORT_LINKUP",
+ "Base port ethernet linkup: mac = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_ETHPORT_LINKDOWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ETHPORT_LINKDOWN",
+ "Base port ethernet linkdown: mac = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_ETHPORT_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ETHPORT_ENABLE",
+ "Base port ethernet interface enabled: mac = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_ETHPORT_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ETHPORT_DISABLE",
+ "Base port ethernet interface disabled: mac = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+
+
+
+/* messages define for BFA_AEN_CAT_IOC Module */
+{BFA_AEN_IOC_HBGOOD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_IOC_HBGOOD",
+ "Heart Beat of IOC %d is good.",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_HBFAIL, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_CRITICAL,
+ "BFA_AEN_IOC_HBFAIL",
+ "Heart Beat of IOC %d has failed.",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_IOC_ENABLE",
+ "IOC %d is enabled.",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_IOC_DISABLE",
+ "IOC %d is disabled.",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_IOC_FWMISMATCH, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_CRITICAL, "BFA_AEN_IOC_FWMISMATCH",
+ "Running firmware version is incompatible with the driver version.",
+ (0), 0},
+
+
+
+
+/* messages define for BFA_AEN_CAT_ITNIM Module */
+{BFA_AEN_ITNIM_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ITNIM_ONLINE",
+ "Target (WWN = %s) is online for initiator (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_ITNIM_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_ITNIM_OFFLINE",
+ "Target (WWN = %s) offlined by initiator (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_ITNIM_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_ITNIM_DISCONNECT",
+ "Target (WWN = %s) connectivity lost for initiator (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+
+
+
+/* messages define for BFA_AEN_CAT_LPORT Module */
+{BFA_AEN_LPORT_NEW, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_LPORT_NEW",
+ "New logical port created: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_DELETE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_LPORT_DELETE",
+ "Logical port deleted: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_LPORT_ONLINE",
+ "Logical port online: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_LPORT_OFFLINE",
+ "Logical port taken offline: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_LPORT_DISCONNECT",
+ "Logical port lost fabric connectivity: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_NEW_PROP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_LPORT_NEW_PROP",
+ "New virtual port created using proprietary interface: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_DELETE_PROP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "BFA_AEN_LPORT_DELETE_PROP",
+ "Virtual port deleted using proprietary interface: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_NEW_STANDARD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "BFA_AEN_LPORT_NEW_STANDARD",
+ "New virtual port created using standard interface: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_DELETE_STANDARD, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "BFA_AEN_LPORT_DELETE_STANDARD",
+ "Virtual port deleted using standard interface: WWN = %s, Role = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_LPORT_NPIV_DUP_WWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_DUP_WWN",
+ "Virtual port login failed. Duplicate WWN = %s reported by fabric.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_LPORT_NPIV_FABRIC_MAX, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_FABRIC_MAX",
+ "Virtual port (WWN = %s) login failed. Max NPIV ports already exist in"
+ " fabric/fport.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_LPORT_NPIV_UNKNOWN, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_LPORT_NPIV_UNKNOWN",
+ "Virtual port (WWN = %s) login failed.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+
+
+
+/* messages define for BFA_AEN_CAT_PORT Module */
+{BFA_AEN_PORT_ONLINE, BFA_LOG_ATTR_NONE, BFA_LOG_INFO, "BFA_AEN_PORT_ONLINE",
+ "Base port online: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING,
+ "BFA_AEN_PORT_OFFLINE",
+ "Base port offline: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_RLIR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_PORT_RLIR",
+ "RLIR event not supported.",
+ (0), 0},
+
+{BFA_AEN_PORT_SFP_INSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_PORT_SFP_INSERT",
+ "New SFP found: WWN/MAC = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_SFP_REMOVE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_REMOVE",
+ "SFP removed: WWN/MAC = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_SFP_POM, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING,
+ "BFA_AEN_PORT_SFP_POM",
+ "SFP POM level to %s: WWN/MAC = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_PORT_ENABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_PORT_ENABLE",
+ "Base port enabled: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_DISABLE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_PORT_DISABLE",
+ "Base port disabled: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_AUTH_ON, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_PORT_AUTH_ON",
+ "Authentication successful for base port: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_AUTH_OFF, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR,
+ "BFA_AEN_PORT_AUTH_OFF",
+ "Authentication unsuccessful for base port: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR,
+ "BFA_AEN_PORT_DISCONNECT",
+ "Base port (WWN = %s) lost fabric connectivity.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_QOS_NEG, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_WARNING,
+ "BFA_AEN_PORT_QOS_NEG",
+ "QOS negotiation failed for base port: WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_FABRIC_NAME_CHANGE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_PORT_FABRIC_NAME_CHANGE",
+ "Base port WWN = %s, Fabric WWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_PORT_SFP_ACCESS_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_ACCESS_ERROR",
+ "SFP access error: WWN/MAC = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_AEN_PORT_SFP_UNSUPPORT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_WARNING, "BFA_AEN_PORT_SFP_UNSUPPORT",
+ "Unsupported SFP found: WWN/MAC = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+
+
+
+/* messages define for BFA_AEN_CAT_RPORT Module */
+{BFA_AEN_RPORT_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_RPORT_ONLINE",
+ "Remote port (WWN = %s) online for logical port (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_RPORT_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_RPORT_OFFLINE",
+ "Remote port (WWN = %s) offlined by logical port (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_RPORT_DISCONNECT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_ERROR, "BFA_AEN_RPORT_DISCONNECT",
+ "Remote port (WWN = %s) connectivity lost for logical port (WWN = %s).",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) | 0), 2},
+
+{BFA_AEN_RPORT_QOS_PRIO, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_RPORT_QOS_PRIO",
+ "QOS priority changed to %s: RPWWN = %s and LPWWN = %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
+
+{BFA_AEN_RPORT_QOS_FLOWID, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "BFA_AEN_RPORT_QOS_FLOWID",
+ "QOS flow ID changed to %d: RPWWN = %s and LPWWN = %s.",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
+
+
+
+
+/* messages define for FCS Module */
+{BFA_LOG_FCS_FABRIC_NOSWITCH, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "FCS_FABRIC_NOSWITCH",
+ "No switched fabric presence is detected.",
+ (0), 0},
+
+{BFA_LOG_FCS_FABRIC_ISOLATED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "FCS_FABRIC_ISOLATED",
+ "Port is isolated due to VF_ID mismatch. PWWN: %s, Port VF_ID: %04x and"
+ " switch port VF_ID: %04x.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_X << BFA_LOG_ARG1) |
+ (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3},
+
+
+
+
+/* messages define for HAL Module */
+{BFA_LOG_HAL_ASSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR,
+ "HAL_ASSERT",
+ "Assertion failure: %s:%d: %s",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
+
+{BFA_LOG_HAL_HEARTBEAT_FAILURE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_CRITICAL, "HAL_HEARTBEAT_FAILURE",
+ "Firmware heartbeat failure at %d",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_HAL_FCPIM_PARM_INVALID, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "HAL_FCPIM_PARM_INVALID",
+ "Driver configuration %s value %d is invalid. Value should be within"
+ " %d and %d.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
+ (BFA_LOG_D << BFA_LOG_ARG2) | (BFA_LOG_D << BFA_LOG_ARG3) | 0), 4},
+
+{BFA_LOG_HAL_SM_ASSERT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_ERROR,
+ "HAL_SM_ASSERT",
+ "SM Assertion failure: %s:%d: event = %d",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
+ (BFA_LOG_D << BFA_LOG_ARG2) | 0), 3},
+
+
+
+
+/* messages define for LINUX Module */
+{BFA_LOG_LINUX_DEVICE_CLAIMED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_DEVICE_CLAIMED",
+ "bfa device at %s claimed.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_HASH_INIT_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_HASH_INIT_FAILED",
+ "Hash table initialization failure for the port %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_SYSFS_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_SYSFS_FAILED",
+ "sysfs file creation failure for the port %s.",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_MEM_ALLOC_FAILED, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_MEM_ALLOC_FAILED",
+ "Memory allocation failed: %s. ",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_DRIVER_REGISTRATION_FAILED,
+ BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_DRIVER_REGISTRATION_FAILED",
+ "%s. ",
+ ((BFA_LOG_S << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_ITNIM_FREE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_ITNIM_FREE",
+ "scsi%d: FCID: %s WWPN: %s",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_S << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | 0), 3},
+
+{BFA_LOG_LINUX_ITNIM_ONLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_ITNIM_ONLINE",
+ "Target: %d:0:%d FCID: %s WWPN: %s",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | (BFA_LOG_S << BFA_LOG_ARG3) | 0), 4},
+
+{BFA_LOG_LINUX_ITNIM_OFFLINE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_ITNIM_OFFLINE",
+ "Target: %d:0:%d FCID: %s WWPN: %s",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_D << BFA_LOG_ARG1) |
+ (BFA_LOG_S << BFA_LOG_ARG2) | (BFA_LOG_S << BFA_LOG_ARG3) | 0), 4},
+
+{BFA_LOG_LINUX_SCSI_HOST_FREE, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_SCSI_HOST_FREE",
+ "Free scsi%d",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | 0), 1},
+
+{BFA_LOG_LINUX_SCSI_ABORT, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG, BFA_LOG_INFO,
+ "LINUX_SCSI_ABORT",
+ "scsi%d: abort cmnd %p, iotag %x",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) |
+ (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3},
+
+{BFA_LOG_LINUX_SCSI_ABORT_COMP, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "LINUX_SCSI_ABORT_COMP",
+ "scsi%d: complete abort 0x%p, iotag 0x%x",
+ ((BFA_LOG_D << BFA_LOG_ARG0) | (BFA_LOG_P << BFA_LOG_ARG1) |
+ (BFA_LOG_X << BFA_LOG_ARG2) | 0), 3},
+
+
+
+
+/* messages define for WDRV Module */
+{BFA_LOG_WDRV_IOC_INIT_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_IOC_INIT_ERROR",
+ "IOC initialization has failed.",
+ (0), 0},
+
+{BFA_LOG_WDRV_IOC_INTERNAL_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_IOC_INTERNAL_ERROR",
+ "IOC internal error. ",
+ (0), 0},
+
+{BFA_LOG_WDRV_IOC_START_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_IOC_START_ERROR",
+ "IOC could not be started. ",
+ (0), 0},
+
+{BFA_LOG_WDRV_IOC_STOP_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_IOC_STOP_ERROR",
+ "IOC could not be stopped. ",
+ (0), 0},
+
+{BFA_LOG_WDRV_INSUFFICIENT_RESOURCES, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_INSUFFICIENT_RESOURCES",
+ "Insufficient memory. ",
+ (0), 0},
+
+{BFA_LOG_WDRV_BASE_ADDRESS_MAP_ERROR, BFA_LOG_ATTR_NONE | BFA_LOG_ATTR_LOG,
+ BFA_LOG_INFO, "WDRV_BASE_ADDRESS_MAP_ERROR",
+ "Unable to map the IOC onto the system address space. ",
+ (0), 0},
+
+
+{0, 0, 0, "", "", 0, 0},
+};
diff --git a/drivers/scsi/bfa/bfa_lps.c b/drivers/scsi/bfa/bfa_lps.c
new file mode 100644
index 000000000000..9844b45412b6
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_lps.c
@@ -0,0 +1,782 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <bfi/bfi_lps.h>
+#include <cs/bfa_debug.h>
+
+BFA_TRC_FILE(HAL, LPS);
+BFA_MODULE(lps);
+
+#define BFA_LPS_MIN_LPORTS (1)
+#define BFA_LPS_MAX_LPORTS (256)
+
+/**
+ * forward declarations
+ */
+static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len,
+ u32 *dm_len);
+static void bfa_lps_attach(struct bfa_s *bfa, void *bfad,
+ struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo,
+ struct bfa_pcidev_s *pcidev);
+static void bfa_lps_initdone(struct bfa_s *bfa);
+static void bfa_lps_detach(struct bfa_s *bfa);
+static void bfa_lps_start(struct bfa_s *bfa);
+static void bfa_lps_stop(struct bfa_s *bfa);
+static void bfa_lps_iocdisable(struct bfa_s *bfa);
+static void bfa_lps_login_rsp(struct bfa_s *bfa,
+ struct bfi_lps_login_rsp_s *rsp);
+static void bfa_lps_logout_rsp(struct bfa_s *bfa,
+ struct bfi_lps_logout_rsp_s *rsp);
+static void bfa_lps_reqq_resume(void *lps_arg);
+static void bfa_lps_free(struct bfa_lps_s *lps);
+static void bfa_lps_send_login(struct bfa_lps_s *lps);
+static void bfa_lps_send_logout(struct bfa_lps_s *lps);
+static void bfa_lps_login_comp(struct bfa_lps_s *lps);
+static void bfa_lps_logout_comp(struct bfa_lps_s *lps);
+
+
+/**
+ * lps_pvt BFA LPS private functions
+ */
+
+enum bfa_lps_event {
+ BFA_LPS_SM_LOGIN = 1, /* login request from user */
+ BFA_LPS_SM_LOGOUT = 2, /* logout request from user */
+ BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */
+ BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */
+ BFA_LPS_SM_DELETE = 5, /* lps delete from user */
+ BFA_LPS_SM_OFFLINE = 6, /* Link is offline */
+};
+
+static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event);
+static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event);
+static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps,
+ enum bfa_lps_event event);
+static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event);
+static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event);
+static void bfa_lps_sm_logowait(struct bfa_lps_s *lps,
+ enum bfa_lps_event event);
+
+/**
+ * Init state -- no login
+ */
+static void
+bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_LOGIN:
+ if (bfa_reqq_full(lps->bfa, lps->reqq)) {
+ bfa_sm_set_state(lps, bfa_lps_sm_loginwait);
+ bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe);
+ } else {
+ bfa_sm_set_state(lps, bfa_lps_sm_login);
+ bfa_lps_send_login(lps);
+ }
+ break;
+
+ case BFA_LPS_SM_LOGOUT:
+ bfa_lps_logout_comp(lps);
+ break;
+
+ case BFA_LPS_SM_DELETE:
+ bfa_lps_free(lps);
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ break;
+
+ case BFA_LPS_SM_FWRSP:
+ /* Could happen when fabric detects loopback and discards
+ * the lps request. Fw will eventually sent out the timeout
+ * Just ignore
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * login is in progress -- awaiting response from firmware
+ */
+static void
+bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_FWRSP:
+ if (lps->status == BFA_STATUS_OK)
+ bfa_sm_set_state(lps, bfa_lps_sm_online);
+ else
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_lps_login_comp(lps);
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * login pending - awaiting space in request queue
+ */
+static void
+bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_RESUME:
+ bfa_sm_set_state(lps, bfa_lps_sm_login);
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_reqq_wcancel(&lps->wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * login complete
+ */
+static void
+bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_LOGOUT:
+ if (bfa_reqq_full(lps->bfa, lps->reqq)) {
+ bfa_sm_set_state(lps, bfa_lps_sm_logowait);
+ bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe);
+ } else {
+ bfa_sm_set_state(lps, bfa_lps_sm_logout);
+ bfa_lps_send_logout(lps);
+ }
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ case BFA_LPS_SM_DELETE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * logout in progress - awaiting firmware response
+ */
+static void
+bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_FWRSP:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_lps_logout_comp(lps);
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * logout pending -- awaiting space in request queue
+ */
+static void
+bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event)
+{
+ bfa_trc(lps->bfa, lps->lp_tag);
+ bfa_trc(lps->bfa, event);
+
+ switch (event) {
+ case BFA_LPS_SM_RESUME:
+ bfa_sm_set_state(lps, bfa_lps_sm_logout);
+ bfa_lps_send_logout(lps);
+ break;
+
+ case BFA_LPS_SM_OFFLINE:
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ bfa_reqq_wcancel(&lps->wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * lps_pvt BFA LPS private functions
+ */
+
+/**
+ * return memory requirement
+ */
+static void
+bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len)
+{
+ if (cfg->drvcfg.min_cfg)
+ *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS;
+ else
+ *ndm_len += sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS;
+}
+
+/**
+ * bfa module attach at initialization time
+ */
+static void
+bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps;
+ int i;
+
+ bfa_os_memset(mod, 0, sizeof(struct bfa_lps_mod_s));
+ mod->num_lps = BFA_LPS_MAX_LPORTS;
+ if (cfg->drvcfg.min_cfg)
+ mod->num_lps = BFA_LPS_MIN_LPORTS;
+ else
+ mod->num_lps = BFA_LPS_MAX_LPORTS;
+ mod->lps_arr = lps = (struct bfa_lps_s *) bfa_meminfo_kva(meminfo);
+
+ bfa_meminfo_kva(meminfo) += mod->num_lps * sizeof(struct bfa_lps_s);
+
+ INIT_LIST_HEAD(&mod->lps_free_q);
+ INIT_LIST_HEAD(&mod->lps_active_q);
+
+ for (i = 0; i < mod->num_lps; i++, lps++) {
+ lps->bfa = bfa;
+ lps->lp_tag = (u8) i;
+ lps->reqq = BFA_REQQ_LPS;
+ bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps);
+ list_add_tail(&lps->qe, &mod->lps_free_q);
+ }
+}
+
+static void
+bfa_lps_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_lps_detach(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_lps_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_lps_stop(struct bfa_s *bfa)
+{
+}
+
+/**
+ * IOC in disabled state -- consider all lps offline
+ */
+static void
+bfa_lps_iocdisable(struct bfa_s *bfa)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &mod->lps_active_q) {
+ lps = (struct bfa_lps_s *) qe;
+ bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE);
+ }
+}
+
+/**
+ * Firmware login response
+ */
+static void
+bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps;
+
+ bfa_assert(rsp->lp_tag < mod->num_lps);
+ lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag);
+
+ lps->status = rsp->status;
+ switch (rsp->status) {
+ case BFA_STATUS_OK:
+ lps->fport = rsp->f_port;
+ lps->npiv_en = rsp->npiv_en;
+ lps->lp_pid = rsp->lp_pid;
+ lps->pr_bbcred = bfa_os_ntohs(rsp->bb_credit);
+ lps->pr_pwwn = rsp->port_name;
+ lps->pr_nwwn = rsp->node_name;
+ lps->auth_req = rsp->auth_req;
+ lps->lp_mac = rsp->lp_mac;
+ lps->brcd_switch = rsp->brcd_switch;
+ lps->fcf_mac = rsp->fcf_mac;
+
+ break;
+
+ case BFA_STATUS_FABRIC_RJT:
+ lps->lsrjt_rsn = rsp->lsrjt_rsn;
+ lps->lsrjt_expl = rsp->lsrjt_expl;
+
+ break;
+
+ case BFA_STATUS_EPROTOCOL:
+ lps->ext_status = rsp->ext_status;
+
+ break;
+
+ default:
+ /* Nothing to do with other status */
+ break;
+ }
+
+ bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
+}
+
+/**
+ * Firmware logout response
+ */
+static void
+bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps;
+
+ bfa_assert(rsp->lp_tag < mod->num_lps);
+ lps = BFA_LPS_FROM_TAG(mod, rsp->lp_tag);
+
+ bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP);
+}
+
+/**
+ * Space is available in request queue, resume queueing request to firmware.
+ */
+static void
+bfa_lps_reqq_resume(void *lps_arg)
+{
+ struct bfa_lps_s *lps = lps_arg;
+
+ bfa_sm_send_event(lps, BFA_LPS_SM_RESUME);
+}
+
+/**
+ * lps is freed -- triggered by vport delete
+ */
+static void
+bfa_lps_free(struct bfa_lps_s *lps)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa);
+
+ list_del(&lps->qe);
+ list_add_tail(&lps->qe, &mod->lps_free_q);
+}
+
+/**
+ * send login request to firmware
+ */
+static void
+bfa_lps_send_login(struct bfa_lps_s *lps)
+{
+ struct bfi_lps_login_req_s *m;
+
+ m = bfa_reqq_next(lps->bfa, lps->reqq);
+ bfa_assert(m);
+
+ bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ,
+ bfa_lpuid(lps->bfa));
+
+ m->lp_tag = lps->lp_tag;
+ m->alpa = lps->alpa;
+ m->pdu_size = bfa_os_htons(lps->pdusz);
+ m->pwwn = lps->pwwn;
+ m->nwwn = lps->nwwn;
+ m->fdisc = lps->fdisc;
+ m->auth_en = lps->auth_en;
+
+ bfa_reqq_produce(lps->bfa, lps->reqq);
+}
+
+/**
+ * send logout request to firmware
+ */
+static void
+bfa_lps_send_logout(struct bfa_lps_s *lps)
+{
+ struct bfi_lps_logout_req_s *m;
+
+ m = bfa_reqq_next(lps->bfa, lps->reqq);
+ bfa_assert(m);
+
+ bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ,
+ bfa_lpuid(lps->bfa));
+
+ m->lp_tag = lps->lp_tag;
+ m->port_name = lps->pwwn;
+ bfa_reqq_produce(lps->bfa, lps->reqq);
+}
+
+/**
+ * Indirect login completion handler for non-fcs
+ */
+static void
+bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete)
+{
+ struct bfa_lps_s *lps = arg;
+
+ if (!complete)
+ return;
+
+ if (lps->fdisc)
+ bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status);
+ else
+ bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
+}
+
+/**
+ * Login completion handler -- direct call for fcs, queue for others
+ */
+static void
+bfa_lps_login_comp(struct bfa_lps_s *lps)
+{
+ if (!lps->bfa->fcs) {
+ bfa_cb_queue(lps->bfa, &lps->hcb_qe,
+ bfa_lps_login_comp_cb, lps);
+ return;
+ }
+
+ if (lps->fdisc)
+ bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status);
+ else
+ bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status);
+}
+
+/**
+ * Indirect logout completion handler for non-fcs
+ */
+static void
+bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete)
+{
+ struct bfa_lps_s *lps = arg;
+
+ if (!complete)
+ return;
+
+ if (lps->fdisc)
+ bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
+ else
+ bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg);
+}
+
+/**
+ * Logout completion handler -- direct call for fcs, queue for others
+ */
+static void
+bfa_lps_logout_comp(struct bfa_lps_s *lps)
+{
+ if (!lps->bfa->fcs) {
+ bfa_cb_queue(lps->bfa, &lps->hcb_qe,
+ bfa_lps_logout_comp_cb, lps);
+ return;
+ }
+ if (lps->fdisc)
+ bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg);
+ else
+ bfa_cb_lps_flogo_comp(lps->bfa->bfad, lps->uarg);
+}
+
+
+
+/**
+ * lps_public BFA LPS public functions
+ */
+
+/**
+ * Allocate a lport srvice tag.
+ */
+struct bfa_lps_s *
+bfa_lps_alloc(struct bfa_s *bfa)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps = NULL;
+
+ bfa_q_deq(&mod->lps_free_q, &lps);
+
+ if (lps == NULL)
+ return NULL;
+
+ list_add_tail(&lps->qe, &mod->lps_active_q);
+
+ bfa_sm_set_state(lps, bfa_lps_sm_init);
+ return lps;
+}
+
+/**
+ * Free lport service tag. This can be called anytime after an alloc.
+ * No need to wait for any pending login/logout completions.
+ */
+void
+bfa_lps_delete(struct bfa_lps_s *lps)
+{
+ bfa_sm_send_event(lps, BFA_LPS_SM_DELETE);
+}
+
+/**
+ * Initiate a lport login.
+ */
+void
+bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz,
+ wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en)
+{
+ lps->uarg = uarg;
+ lps->alpa = alpa;
+ lps->pdusz = pdusz;
+ lps->pwwn = pwwn;
+ lps->nwwn = nwwn;
+ lps->fdisc = BFA_FALSE;
+ lps->auth_en = auth_en;
+ bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
+}
+
+/**
+ * Initiate a lport fdisc login.
+ */
+void
+bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn,
+ wwn_t nwwn)
+{
+ lps->uarg = uarg;
+ lps->alpa = 0;
+ lps->pdusz = pdusz;
+ lps->pwwn = pwwn;
+ lps->nwwn = nwwn;
+ lps->fdisc = BFA_TRUE;
+ lps->auth_en = BFA_FALSE;
+ bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN);
+}
+
+/**
+ * Initiate a lport logout (flogi).
+ */
+void
+bfa_lps_flogo(struct bfa_lps_s *lps)
+{
+ bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
+}
+
+/**
+ * Initiate a lport FDSIC logout.
+ */
+void
+bfa_lps_fdisclogo(struct bfa_lps_s *lps)
+{
+ bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT);
+}
+
+/**
+ * Discard a pending login request -- should be called only for
+ * link down handling.
+ */
+void
+bfa_lps_discard(struct bfa_lps_s *lps)
+{
+ bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE);
+}
+
+/**
+ * Return lport services tag
+ */
+u8
+bfa_lps_get_tag(struct bfa_lps_s *lps)
+{
+ return lps->lp_tag;
+}
+
+/**
+ * Return lport services tag given the pid
+ */
+u8
+bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid)
+{
+ struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa);
+ struct bfa_lps_s *lps;
+ int i;
+
+ for (i = 0, lps = mod->lps_arr; i < mod->num_lps; i++, lps++) {
+ if (lps->lp_pid == pid)
+ return lps->lp_tag;
+ }
+
+ /* Return base port tag anyway */
+ return 0;
+}
+
+/**
+ * return if fabric login indicates support for NPIV
+ */
+bfa_boolean_t
+bfa_lps_is_npiv_en(struct bfa_lps_s *lps)
+{
+ return lps->npiv_en;
+}
+
+/**
+ * Return TRUE if attached to F-Port, else return FALSE
+ */
+bfa_boolean_t
+bfa_lps_is_fport(struct bfa_lps_s *lps)
+{
+ return lps->fport;
+}
+
+/**
+ * Return TRUE if attached to a Brocade Fabric
+ */
+bfa_boolean_t
+bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps)
+{
+ return lps->brcd_switch;
+}
+/**
+ * return TRUE if authentication is required
+ */
+bfa_boolean_t
+bfa_lps_is_authreq(struct bfa_lps_s *lps)
+{
+ return lps->auth_req;
+}
+
+bfa_eproto_status_t
+bfa_lps_get_extstatus(struct bfa_lps_s *lps)
+{
+ return lps->ext_status;
+}
+
+/**
+ * return port id assigned to the lport
+ */
+u32
+bfa_lps_get_pid(struct bfa_lps_s *lps)
+{
+ return lps->lp_pid;
+}
+
+/**
+ * Return bb_credit assigned in FLOGI response
+ */
+u16
+bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps)
+{
+ return lps->pr_bbcred;
+}
+
+/**
+ * Return peer port name
+ */
+wwn_t
+bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps)
+{
+ return lps->pr_pwwn;
+}
+
+/**
+ * Return peer node name
+ */
+wwn_t
+bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps)
+{
+ return lps->pr_nwwn;
+}
+
+/**
+ * return reason code if login request is rejected
+ */
+u8
+bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps)
+{
+ return lps->lsrjt_rsn;
+}
+
+/**
+ * return explanation code if login request is rejected
+ */
+u8
+bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps)
+{
+ return lps->lsrjt_expl;
+}
+
+
+/**
+ * LPS firmware message class handler.
+ */
+void
+bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ union bfi_lps_i2h_msg_u msg;
+
+ bfa_trc(bfa, m->mhdr.msg_id);
+ msg.msg = m;
+
+ switch (m->mhdr.msg_id) {
+ case BFI_LPS_H2I_LOGIN_RSP:
+ bfa_lps_login_rsp(bfa, msg.login_rsp);
+ break;
+
+ case BFI_LPS_H2I_LOGOUT_RSP:
+ bfa_lps_logout_rsp(bfa, msg.logout_rsp);
+ break;
+
+ default:
+ bfa_trc(bfa, m->mhdr.msg_id);
+ bfa_assert(0);
+ }
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_lps_priv.h b/drivers/scsi/bfa/bfa_lps_priv.h
new file mode 100644
index 000000000000..d16c6ce995df
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_lps_priv.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_LPS_PRIV_H__
+#define __BFA_LPS_PRIV_H__
+
+#include <bfa_svc.h>
+
+struct bfa_lps_mod_s {
+ struct list_head lps_free_q;
+ struct list_head lps_active_q;
+ struct bfa_lps_s *lps_arr;
+ int num_lps;
+};
+
+#define BFA_LPS_MOD(__bfa) (&(__bfa)->modules.lps_mod)
+#define BFA_LPS_FROM_TAG(__mod, __tag) (&(__mod)->lps_arr[__tag])
+
+/*
+ * external functions
+ */
+void bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+
+#endif /* __BFA_LPS_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_module.c b/drivers/scsi/bfa/bfa_module.c
new file mode 100644
index 000000000000..32eda8e1ec65
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_module.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <bfa.h>
+#include <defs/bfa_defs_pci.h>
+#include <cs/bfa_debug.h>
+#include <bfa_iocfc.h>
+
+/**
+ * BFA module list terminated by NULL
+ */
+struct bfa_module_s *hal_mods[] = {
+ &hal_mod_sgpg,
+ &hal_mod_pport,
+ &hal_mod_fcxp,
+ &hal_mod_lps,
+ &hal_mod_uf,
+ &hal_mod_rport,
+ &hal_mod_fcpim,
+#ifdef BFA_CFG_PBIND
+ &hal_mod_pbind,
+#endif
+ NULL
+};
+
+/**
+ * Message handlers for various modules.
+ */
+bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = {
+ bfa_isr_unhandled, /* NONE */
+ bfa_isr_unhandled, /* BFI_MC_IOC */
+ bfa_isr_unhandled, /* BFI_MC_DIAG */
+ bfa_isr_unhandled, /* BFI_MC_FLASH */
+ bfa_isr_unhandled, /* BFI_MC_CEE */
+ bfa_pport_isr, /* BFI_MC_PORT */
+ bfa_isr_unhandled, /* BFI_MC_IOCFC */
+ bfa_isr_unhandled, /* BFI_MC_LL */
+ bfa_uf_isr, /* BFI_MC_UF */
+ bfa_fcxp_isr, /* BFI_MC_FCXP */
+ bfa_lps_isr, /* BFI_MC_LPS */
+ bfa_rport_isr, /* BFI_MC_RPORT */
+ bfa_itnim_isr, /* BFI_MC_ITNIM */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_READ */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_WRITE */
+ bfa_isr_unhandled, /* BFI_MC_IOIM_IO */
+ bfa_ioim_isr, /* BFI_MC_IOIM */
+ bfa_ioim_good_comp_isr, /* BFI_MC_IOIM_IOCOM */
+ bfa_tskim_isr, /* BFI_MC_TSKIM */
+ bfa_isr_unhandled, /* BFI_MC_SBOOT */
+ bfa_isr_unhandled, /* BFI_MC_IPFC */
+ bfa_isr_unhandled, /* BFI_MC_PORT */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+ bfa_isr_unhandled, /* --------- */
+};
+
+/**
+ * Message handlers for mailbox command classes
+ */
+bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = {
+ NULL,
+ NULL, /* BFI_MC_IOC */
+ NULL, /* BFI_MC_DIAG */
+ NULL, /* BFI_MC_FLASH */
+ NULL, /* BFI_MC_CEE */
+ NULL, /* BFI_MC_PORT */
+ bfa_iocfc_isr, /* BFI_MC_IOCFC */
+ NULL,
+};
+
diff --git a/drivers/scsi/bfa/bfa_modules_priv.h b/drivers/scsi/bfa/bfa_modules_priv.h
new file mode 100644
index 000000000000..96f70534593c
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_modules_priv.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_MODULES_PRIV_H__
+#define __BFA_MODULES_PRIV_H__
+
+#include "bfa_uf_priv.h"
+#include "bfa_port_priv.h"
+#include "bfa_rport_priv.h"
+#include "bfa_fcxp_priv.h"
+#include "bfa_lps_priv.h"
+#include "bfa_fcpim_priv.h"
+#include <cee/bfa_cee.h>
+#include <port/bfa_port.h>
+
+
+struct bfa_modules_s {
+ struct bfa_pport_s pport; /* physical port module */
+ struct bfa_fcxp_mod_s fcxp_mod; /* fcxp module */
+ struct bfa_lps_mod_s lps_mod; /* fcxp module */
+ struct bfa_uf_mod_s uf_mod; /* unsolicited frame module */
+ struct bfa_rport_mod_s rport_mod; /* remote port module */
+ struct bfa_fcpim_mod_s fcpim_mod; /* FCP initiator module */
+ struct bfa_sgpg_mod_s sgpg_mod; /* SG page module */
+ struct bfa_cee_s cee; /* CEE Module */
+ struct bfa_port_s port; /* Physical port module */
+};
+
+#endif /* __BFA_MODULES_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_os_inc.h b/drivers/scsi/bfa/bfa_os_inc.h
new file mode 100644
index 000000000000..10a89f75fa94
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_os_inc.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * Contains declarations all OS Specific files needed for BFA layer
+ */
+
+#ifndef __BFA_OS_INC_H__
+#define __BFA_OS_INC_H__
+
+#ifndef __KERNEL__
+#include <stdint.h>
+#else
+#include <linux/types.h>
+
+#include <linux/version.h>
+#include <linux/pci.h>
+
+#include <linux/dma-mapping.h>
+#define SET_MODULE_VERSION(VER)
+
+#include <linux/idr.h>
+
+#include <linux/interrupt.h>
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+
+#include <linux/workqueue.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport_fc.h>
+#include <scsi/scsi_transport.h>
+
+#define BFA_ERR KERN_ERR
+#define BFA_WARNING KERN_WARNING
+#define BFA_NOTICE KERN_NOTICE
+#define BFA_INFO KERN_INFO
+#define BFA_DEBUG KERN_DEBUG
+
+#define LOG_BFAD_INIT 0x00000001
+#define LOG_FCP_IO 0x00000002
+
+#ifdef DEBUG
+#define BFA_LOG_TRACE(bfad, level, mask, fmt, arg...) \
+ BFA_LOG(bfad, level, mask, fmt, ## arg)
+#define BFA_DEV_TRACE(bfad, level, fmt, arg...) \
+ BFA_DEV_PRINTF(bfad, level, fmt, ## arg)
+#define BFA_TRACE(level, fmt, arg...) \
+ BFA_PRINTF(level, fmt, ## arg)
+#else
+#define BFA_LOG_TRACE(bfad, level, mask, fmt, arg...)
+#define BFA_DEV_TRACE(bfad, level, fmt, arg...)
+#define BFA_TRACE(level, fmt, arg...)
+#endif
+
+#define BFA_ASSERT(p) do { \
+ if (!(p)) { \
+ printk(KERN_ERR "assert(%s) failed at %s:%d\n", \
+ #p, __FILE__, __LINE__); \
+ BUG(); \
+ } \
+} while (0)
+
+
+#define BFA_LOG(bfad, level, mask, fmt, arg...) \
+do { \
+ if (((mask) & (((struct bfad_s *)(bfad))-> \
+ cfg_data[cfg_log_mask])) || (level[1] <= '3')) \
+ dev_printk(level, &(((struct bfad_s *) \
+ (bfad))->pcidev->dev), fmt, ##arg); \
+} while (0)
+
+#ifndef BFA_DEV_PRINTF
+#define BFA_DEV_PRINTF(bfad, level, fmt, arg...) \
+ dev_printk(level, &(((struct bfad_s *) \
+ (bfad))->pcidev->dev), fmt, ##arg);
+#endif
+
+#define BFA_PRINTF(level, fmt, arg...) \
+ printk(level fmt, ##arg);
+
+int bfa_os_MWB(void *);
+
+#define bfa_os_mmiowb() mmiowb()
+
+#define bfa_swap_3b(_x) \
+ ((((_x) & 0xff) << 16) | \
+ ((_x) & 0x00ff00) | \
+ (((_x) & 0xff0000) >> 16))
+
+#define bfa_swap_8b(_x) \
+ ((((_x) & 0xff00000000000000ull) >> 56) \
+ | (((_x) & 0x00ff000000000000ull) >> 40) \
+ | (((_x) & 0x0000ff0000000000ull) >> 24) \
+ | (((_x) & 0x000000ff00000000ull) >> 8) \
+ | (((_x) & 0x00000000ff000000ull) << 8) \
+ | (((_x) & 0x0000000000ff0000ull) << 24) \
+ | (((_x) & 0x000000000000ff00ull) << 40) \
+ | (((_x) & 0x00000000000000ffull) << 56))
+
+#define bfa_os_swap32(_x) \
+ ((((_x) & 0xff) << 24) | \
+ (((_x) & 0x0000ff00) << 8) | \
+ (((_x) & 0x00ff0000) >> 8) | \
+ (((_x) & 0xff000000) >> 24))
+
+
+#ifndef __BIGENDIAN
+#define bfa_os_htons(_x) ((u16)((((_x) & 0xff00) >> 8) | \
+ (((_x) & 0x00ff) << 8)))
+
+#define bfa_os_htonl(_x) bfa_os_swap32(_x)
+#define bfa_os_htonll(_x) bfa_swap_8b(_x)
+#define bfa_os_hton3b(_x) bfa_swap_3b(_x)
+
+#define bfa_os_wtole(_x) (_x)
+
+#else
+
+#define bfa_os_htons(_x) (_x)
+#define bfa_os_htonl(_x) (_x)
+#define bfa_os_hton3b(_x) (_x)
+#define bfa_os_htonll(_x) (_x)
+#define bfa_os_wtole(_x) bfa_os_swap32(_x)
+
+#endif
+
+#define bfa_os_ntohs(_x) bfa_os_htons(_x)
+#define bfa_os_ntohl(_x) bfa_os_htonl(_x)
+#define bfa_os_ntohll(_x) bfa_os_htonll(_x)
+#define bfa_os_ntoh3b(_x) bfa_os_hton3b(_x)
+
+#define bfa_os_u32(__pa64) ((__pa64) >> 32)
+
+#define bfa_os_memset memset
+#define bfa_os_memcpy memcpy
+#define bfa_os_udelay udelay
+#define bfa_os_vsprintf vsprintf
+
+#define bfa_os_assign(__t, __s) __t = __s
+
+#define bfa_os_addr_t char __iomem *
+#define bfa_os_panic()
+
+#define bfa_os_reg_read(_raddr) bfa_os_wtole(readl(_raddr))
+#define bfa_os_reg_write(_raddr, _val) writel(bfa_os_wtole((_val)), (_raddr))
+#define bfa_os_mem_read(_raddr, _off) \
+ bfa_os_ntohl(readl(((_raddr) + (_off))))
+#define bfa_os_mem_write(_raddr, _off, _val) \
+ writel(bfa_os_htonl((_val)), ((_raddr) + (_off)))
+
+#define BFA_TRC_TS(_trcm) \
+ ({ \
+ struct timeval tv; \
+ \
+ do_gettimeofday(&tv); \
+ (tv.tv_sec*1000000+tv.tv_usec); \
+ })
+
+struct bfa_log_mod_s;
+void bfa_os_printf(struct bfa_log_mod_s *log_mod, u32 msg_id,
+ const char *fmt, ...);
+#endif
+
+#define boolean_t int
+
+/**
+ * For current time stamp, OS API will fill-in
+ */
+struct bfa_timeval_s {
+ u32 tv_sec; /* seconds */
+ u32 tv_usec; /* microseconds */
+};
+
+void bfa_os_gettimeofday(struct bfa_timeval_s *tv);
+
+static inline void
+wwn2str(char *wwn_str, u64 wwn)
+{
+ union {
+ u64 wwn;
+ u8 byte[8];
+ } w;
+
+ w.wwn = wwn;
+ sprintf(wwn_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", w.byte[0],
+ w.byte[1], w.byte[2], w.byte[3], w.byte[4], w.byte[5],
+ w.byte[6], w.byte[7]);
+}
+
+static inline void
+fcid2str(char *fcid_str, u32 fcid)
+{
+ union {
+ u32 fcid;
+ u8 byte[4];
+ } f;
+
+ f.fcid = fcid;
+ sprintf(fcid_str, "%02x:%02x:%02x", f.byte[1], f.byte[2], f.byte[3]);
+}
+
+#endif /* __BFA_OS_INC_H__ */
diff --git a/drivers/scsi/bfa/bfa_port.c b/drivers/scsi/bfa/bfa_port.c
new file mode 100644
index 000000000000..cab19028361a
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_port.c
@@ -0,0 +1,460 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <defs/bfa_defs_port.h>
+#include <cs/bfa_trc.h>
+#include <cs/bfa_log.h>
+#include <cs/bfa_debug.h>
+#include <port/bfa_port.h>
+#include <bfi/bfi.h>
+#include <bfi/bfi_port.h>
+#include <bfa_ioc.h>
+#include <cna/bfa_cna_trcmod.h>
+
+BFA_TRC_FILE(CNA, PORT);
+
+#define bfa_ioc_portid(__ioc) ((__ioc)->port_id)
+#define bfa_lpuid(__arg) bfa_ioc_portid(&(__arg)->ioc)
+
+static void
+bfa_port_stats_swap(struct bfa_port_s *port, union bfa_pport_stats_u *stats)
+{
+ u32 *dip = (u32 *) stats;
+ u32 t0, t1;
+ int i;
+
+ for (i = 0; i < sizeof(union bfa_pport_stats_u) / sizeof(u32);
+ i += 2) {
+ t0 = dip[i];
+ t1 = dip[i + 1];
+#ifdef __BIGENDIAN
+ dip[i] = bfa_os_ntohl(t0);
+ dip[i + 1] = bfa_os_ntohl(t1);
+#else
+ dip[i] = bfa_os_ntohl(t1);
+ dip[i + 1] = bfa_os_ntohl(t0);
+#endif
+ }
+
+ /** todo
+ * QoS stats r also swapped as 64bit; that structure also
+ * has to use 64 bit counters
+ */
+}
+
+/**
+ * bfa_port_enable_isr()
+ *
+ *
+ * @param[in] port - Pointer to the port module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_port_enable_isr(struct bfa_port_s *port, bfa_status_t status)
+{
+ bfa_assert(0);
+}
+
+/**
+ * bfa_port_disable_isr()
+ *
+ *
+ * @param[in] port - Pointer to the port module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_port_disable_isr(struct bfa_port_s *port, bfa_status_t status)
+{
+ bfa_assert(0);
+}
+
+/**
+ * bfa_port_get_stats_isr()
+ *
+ *
+ * @param[in] port - Pointer to the Port module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status)
+{
+ port->stats_status = status;
+ port->stats_busy = BFA_FALSE;
+
+ if (status == BFA_STATUS_OK) {
+ memcpy(port->stats, port->stats_dma.kva,
+ sizeof(union bfa_pport_stats_u));
+ bfa_port_stats_swap(port, port->stats);
+ }
+
+ if (port->stats_cbfn) {
+ port->stats_cbfn(port->stats_cbarg, status);
+ port->stats_cbfn = NULL;
+ }
+}
+
+/**
+ * bfa_port_clear_stats_isr()
+ *
+ *
+ * @param[in] port - Pointer to the Port module
+ * status - Return status from the f/w
+ *
+ * @return void
+ */
+static void
+bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status)
+{
+ port->stats_status = status;
+ port->stats_busy = BFA_FALSE;
+
+ if (port->stats_cbfn) {
+ port->stats_cbfn(port->stats_cbarg, status);
+ port->stats_cbfn = NULL;
+ }
+}
+
+/**
+ * bfa_port_isr()
+ *
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return void
+ */
+static void
+bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m)
+{
+ struct bfa_port_s *port = (struct bfa_port_s *)cbarg;
+ union bfi_port_i2h_msg_u *i2hmsg;
+
+ i2hmsg = (union bfi_port_i2h_msg_u *)m;
+ bfa_trc(port, m->mh.msg_id);
+
+ switch (m->mh.msg_id) {
+ case BFI_PORT_I2H_ENABLE_RSP:
+ if (port->endis_pending == BFA_FALSE)
+ break;
+ bfa_port_enable_isr(port, i2hmsg->enable_rsp.status);
+ break;
+
+ case BFI_PORT_I2H_DISABLE_RSP:
+ if (port->endis_pending == BFA_FALSE)
+ break;
+ bfa_port_disable_isr(port, i2hmsg->disable_rsp.status);
+ break;
+
+ case BFI_PORT_I2H_GET_STATS_RSP:
+ /*
+ * Stats busy flag is still set? (may be cmd timed out)
+ */
+ if (port->stats_busy == BFA_FALSE)
+ break;
+ bfa_port_get_stats_isr(port, i2hmsg->getstats_rsp.status);
+ break;
+
+ case BFI_PORT_I2H_CLEAR_STATS_RSP:
+ if (port->stats_busy == BFA_FALSE)
+ break;
+ bfa_port_clear_stats_isr(port, i2hmsg->clearstats_rsp.status);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * bfa_port_meminfo()
+ *
+ *
+ * @param[in] void
+ *
+ * @return Size of DMA region
+ */
+u32
+bfa_port_meminfo(void)
+{
+ return BFA_ROUNDUP(sizeof(union bfa_pport_stats_u), BFA_DMA_ALIGN_SZ);
+}
+
+/**
+ * bfa_port_mem_claim()
+ *
+ *
+ * @param[in] port Port module pointer
+ * dma_kva Kernel Virtual Address of Port DMA Memory
+ * dma_pa Physical Address of Port DMA Memory
+ *
+ * @return void
+ */
+void
+bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa)
+{
+ port->stats_dma.kva = dma_kva;
+ port->stats_dma.pa = dma_pa;
+}
+
+/**
+ * bfa_port_enable()
+ *
+ * Send the Port enable request to the f/w
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return Status
+ */
+bfa_status_t
+bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn,
+ void *cbarg)
+{
+ struct bfi_port_generic_req_s *m;
+
+ /** todo Not implemented */
+ bfa_assert(0);
+
+ if (!bfa_ioc_is_operational(port->ioc)) {
+ bfa_trc(port, BFA_STATUS_IOC_FAILURE);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+
+ if (port->endis_pending) {
+ bfa_trc(port, BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ m = (struct bfi_port_generic_req_s *)port->endis_mb.msg;
+
+ port->msgtag++;
+ port->endis_cbfn = cbfn;
+ port->endis_cbarg = cbarg;
+ port->endis_pending = BFA_TRUE;
+
+ bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_ENABLE_REQ,
+ bfa_ioc_portid(port->ioc));
+ bfa_ioc_mbox_queue(port->ioc, &port->endis_mb);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_port_disable()
+ *
+ * Send the Port disable request to the f/w
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return Status
+ */
+bfa_status_t
+bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn,
+ void *cbarg)
+{
+ struct bfi_port_generic_req_s *m;
+
+ /** todo Not implemented */
+ bfa_assert(0);
+
+ if (!bfa_ioc_is_operational(port->ioc)) {
+ bfa_trc(port, BFA_STATUS_IOC_FAILURE);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+
+ if (port->endis_pending) {
+ bfa_trc(port, BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ m = (struct bfi_port_generic_req_s *)port->endis_mb.msg;
+
+ port->msgtag++;
+ port->endis_cbfn = cbfn;
+ port->endis_cbarg = cbarg;
+ port->endis_pending = BFA_TRUE;
+
+ bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_DISABLE_REQ,
+ bfa_ioc_portid(port->ioc));
+ bfa_ioc_mbox_queue(port->ioc, &port->endis_mb);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_port_get_stats()
+ *
+ * Send the request to the f/w to fetch Port statistics.
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return Status
+ */
+bfa_status_t
+bfa_port_get_stats(struct bfa_port_s *port, union bfa_pport_stats_u *stats,
+ bfa_port_stats_cbfn_t cbfn, void *cbarg)
+{
+ struct bfi_port_get_stats_req_s *m;
+
+ if (!bfa_ioc_is_operational(port->ioc)) {
+ bfa_trc(port, BFA_STATUS_IOC_FAILURE);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+
+ if (port->stats_busy) {
+ bfa_trc(port, BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ m = (struct bfi_port_get_stats_req_s *)port->stats_mb.msg;
+
+ port->stats = stats;
+ port->stats_cbfn = cbfn;
+ port->stats_cbarg = cbarg;
+ port->stats_busy = BFA_TRUE;
+ bfa_dma_be_addr_set(m->dma_addr, port->stats_dma.pa);
+
+ bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_GET_STATS_REQ,
+ bfa_ioc_portid(port->ioc));
+ bfa_ioc_mbox_queue(port->ioc, &port->stats_mb);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_port_clear_stats()
+ *
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return Status
+ */
+bfa_status_t
+bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn,
+ void *cbarg)
+{
+ struct bfi_port_generic_req_s *m;
+
+ if (!bfa_ioc_is_operational(port->ioc)) {
+ bfa_trc(port, BFA_STATUS_IOC_FAILURE);
+ return BFA_STATUS_IOC_FAILURE;
+ }
+
+ if (port->stats_busy) {
+ bfa_trc(port, BFA_STATUS_DEVBUSY);
+ return BFA_STATUS_DEVBUSY;
+ }
+
+ m = (struct bfi_port_generic_req_s *)port->stats_mb.msg;
+
+ port->stats_cbfn = cbfn;
+ port->stats_cbarg = cbarg;
+ port->stats_busy = BFA_TRUE;
+
+ bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_CLEAR_STATS_REQ,
+ bfa_ioc_portid(port->ioc));
+ bfa_ioc_mbox_queue(port->ioc, &port->stats_mb);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * bfa_port_hbfail()
+ *
+ *
+ * @param[in] Pointer to the Port module data structure.
+ *
+ * @return void
+ */
+void
+bfa_port_hbfail(void *arg)
+{
+ struct bfa_port_s *port = (struct bfa_port_s *)arg;
+
+ /*
+ * Fail any pending get_stats/clear_stats requests
+ */
+ if (port->stats_busy) {
+ if (port->stats_cbfn)
+ port->stats_cbfn(port->dev, BFA_STATUS_FAILED);
+ port->stats_cbfn = NULL;
+ port->stats_busy = BFA_FALSE;
+ }
+
+ /*
+ * Clear any enable/disable is pending
+ */
+ if (port->endis_pending) {
+ if (port->endis_cbfn)
+ port->endis_cbfn(port->dev, BFA_STATUS_FAILED);
+ port->endis_cbfn = NULL;
+ port->endis_pending = BFA_FALSE;
+ }
+}
+
+/**
+ * bfa_port_attach()
+ *
+ *
+ * @param[in] port - Pointer to the Port module data structure
+ * ioc - Pointer to the ioc module data structure
+ * dev - Pointer to the device driver module data structure
+ * The device driver specific mbox ISR functions have
+ * this pointer as one of the parameters.
+ * trcmod -
+ * logmod -
+ *
+ * @return void
+ */
+void
+bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, void *dev,
+ struct bfa_trc_mod_s *trcmod, struct bfa_log_mod_s *logmod)
+{
+ bfa_assert(port);
+
+ port->dev = dev;
+ port->ioc = ioc;
+ port->trcmod = trcmod;
+ port->logmod = logmod;
+
+ port->stats_busy = port->endis_pending = BFA_FALSE;
+ port->stats_cbfn = port->endis_cbfn = NULL;
+
+ bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port);
+ bfa_ioc_hbfail_init(&port->hbfail, bfa_port_hbfail, port);
+ bfa_ioc_hbfail_register(port->ioc, &port->hbfail);
+
+ bfa_trc(port, 0);
+}
+
+/**
+ * bfa_port_detach()
+ *
+ *
+ * @param[in] port - Pointer to the Port module data structure
+ *
+ * @return void
+ */
+void
+bfa_port_detach(struct bfa_port_s *port)
+{
+ bfa_trc(port, 0);
+}
diff --git a/drivers/scsi/bfa/bfa_port_priv.h b/drivers/scsi/bfa/bfa_port_priv.h
new file mode 100644
index 000000000000..51f698a06b6d
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_port_priv.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_PORT_PRIV_H__
+#define __BFA_PORT_PRIV_H__
+
+#include <defs/bfa_defs_pport.h>
+#include <bfi/bfi_pport.h>
+#include "bfa_intr_priv.h"
+
+/**
+ * BFA physical port data structure
+ */
+struct bfa_pport_s {
+ struct bfa_s *bfa; /* parent BFA instance */
+ bfa_sm_t sm; /* port state machine */
+ wwn_t nwwn; /* node wwn of physical port */
+ wwn_t pwwn; /* port wwn of physical oprt */
+ enum bfa_pport_speed speed_sup;
+ /* supported speeds */
+ enum bfa_pport_speed speed; /* current speed */
+ enum bfa_pport_topology topology; /* current topology */
+ u8 myalpa; /* my ALPA in LOOP topology */
+ u8 rsvd[3];
+ struct bfa_pport_cfg_s cfg; /* current port configuration */
+ struct bfa_qos_attr_s qos_attr; /* QoS Attributes */
+ struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */
+ struct bfa_reqq_wait_s reqq_wait;
+ /* to wait for room in reqq */
+ struct bfa_reqq_wait_s svcreq_wait;
+ /* to wait for room in reqq */
+ struct bfa_reqq_wait_s stats_reqq_wait;
+ /* to wait for room in reqq (stats) */
+ void *event_cbarg;
+ void (*event_cbfn) (void *cbarg,
+ bfa_pport_event_t event);
+ union {
+ union bfi_pport_i2h_msg_u i2hmsg;
+ } event_arg;
+ void *bfad; /* BFA driver handle */
+ struct bfa_cb_qe_s hcb_qe; /* BFA callback queue elem */
+ enum bfa_pport_linkstate hcb_event;
+ /* link event for callback */
+ u32 msgtag; /* fimrware msg tag for reply */
+ u8 *stats_kva;
+ u64 stats_pa;
+ union bfa_pport_stats_u *stats; /* pport stats */
+ u32 mypid:24;
+ u32 rsvd_b:8;
+ struct bfa_timer_s timer; /* timer */
+ union bfa_pport_stats_u *stats_ret;
+ /* driver stats location */
+ bfa_status_t stats_status;
+ /* stats/statsclr status */
+ bfa_boolean_t stats_busy;
+ /* outstanding stats/statsclr */
+ bfa_boolean_t stats_qfull;
+ bfa_boolean_t diag_busy;
+ /* diag busy status */
+ bfa_boolean_t beacon;
+ /* port beacon status */
+ bfa_boolean_t link_e2e_beacon;
+ /* link beacon status */
+ bfa_cb_pport_t stats_cbfn;
+ /* driver callback function */
+ void *stats_cbarg;
+ /* *!< user callback arg */
+};
+
+#define BFA_PORT_MOD(__bfa) (&(__bfa)->modules.pport)
+
+/*
+ * public functions
+ */
+void bfa_pport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+#endif /* __BFA_PORT_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_priv.h b/drivers/scsi/bfa/bfa_priv.h
new file mode 100644
index 000000000000..0747a6b26f7b
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_priv.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_PRIV_H__
+#define __BFA_PRIV_H__
+
+#include "bfa_iocfc.h"
+#include "bfa_intr_priv.h"
+#include "bfa_trcmod_priv.h"
+#include "bfa_modules_priv.h"
+#include "bfa_fwimg_priv.h"
+#include <cs/bfa_log.h>
+#include <bfa_timer.h>
+
+/**
+ * Macro to define a new BFA module
+ */
+#define BFA_MODULE(__mod) \
+ static void bfa_ ## __mod ## _meminfo( \
+ struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, \
+ u32 *dm_len); \
+ static void bfa_ ## __mod ## _attach(struct bfa_s *bfa, \
+ void *bfad, struct bfa_iocfc_cfg_s *cfg, \
+ struct bfa_meminfo_s *meminfo, \
+ struct bfa_pcidev_s *pcidev); \
+ static void bfa_ ## __mod ## _initdone(struct bfa_s *bfa); \
+ static void bfa_ ## __mod ## _detach(struct bfa_s *bfa); \
+ static void bfa_ ## __mod ## _start(struct bfa_s *bfa); \
+ static void bfa_ ## __mod ## _stop(struct bfa_s *bfa); \
+ static void bfa_ ## __mod ## _iocdisable(struct bfa_s *bfa); \
+ \
+ extern struct bfa_module_s hal_mod_ ## __mod; \
+ struct bfa_module_s hal_mod_ ## __mod = { \
+ bfa_ ## __mod ## _meminfo, \
+ bfa_ ## __mod ## _attach, \
+ bfa_ ## __mod ## _initdone, \
+ bfa_ ## __mod ## _detach, \
+ bfa_ ## __mod ## _start, \
+ bfa_ ## __mod ## _stop, \
+ bfa_ ## __mod ## _iocdisable, \
+ }
+
+#define BFA_CACHELINE_SZ (256)
+
+/**
+ * Structure used to interact between different BFA sub modules
+ *
+ * Each sub module needs to implement only the entry points relevant to it (and
+ * can leave entry points as NULL)
+ */
+struct bfa_module_s {
+ void (*meminfo) (struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len);
+ void (*attach) (struct bfa_s *bfa, void *bfad,
+ struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo,
+ struct bfa_pcidev_s *pcidev);
+ void (*initdone) (struct bfa_s *bfa);
+ void (*detach) (struct bfa_s *bfa);
+ void (*start) (struct bfa_s *bfa);
+ void (*stop) (struct bfa_s *bfa);
+ void (*iocdisable) (struct bfa_s *bfa);
+};
+
+extern struct bfa_module_s *hal_mods[];
+
+struct bfa_s {
+ void *bfad; /* BFA driver instance */
+ struct bfa_aen_s *aen; /* AEN module */
+ struct bfa_plog_s *plog; /* portlog buffer */
+ struct bfa_log_mod_s *logm; /* driver logging modulen */
+ struct bfa_trc_mod_s *trcmod; /* driver tracing */
+ struct bfa_ioc_s ioc; /* IOC module */
+ struct bfa_iocfc_s iocfc; /* IOCFC module */
+ struct bfa_timer_mod_s timer_mod; /* timer module */
+ struct bfa_modules_s modules; /* BFA modules */
+ struct list_head comp_q; /* pending completions */
+ bfa_boolean_t rme_process; /* RME processing enabled */
+ struct list_head reqq_waitq[BFI_IOC_MAX_CQS];
+ bfa_boolean_t fcs; /* FCS is attached to BFA */
+ struct bfa_msix_s msix;
+};
+
+extern bfa_isr_func_t bfa_isrs[BFI_MC_MAX];
+extern bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[];
+extern bfa_boolean_t bfa_auto_recover;
+extern struct bfa_module_s hal_mod_flash;
+extern struct bfa_module_s hal_mod_fcdiag;
+extern struct bfa_module_s hal_mod_sgpg;
+extern struct bfa_module_s hal_mod_pport;
+extern struct bfa_module_s hal_mod_fcxp;
+extern struct bfa_module_s hal_mod_lps;
+extern struct bfa_module_s hal_mod_uf;
+extern struct bfa_module_s hal_mod_rport;
+extern struct bfa_module_s hal_mod_fcpim;
+extern struct bfa_module_s hal_mod_pbind;
+
+#endif /* __BFA_PRIV_H__ */
+
diff --git a/drivers/scsi/bfa/bfa_rport.c b/drivers/scsi/bfa/bfa_rport.c
new file mode 100644
index 000000000000..3e1990a74258
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_rport.c
@@ -0,0 +1,911 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <cs/bfa_debug.h>
+#include <bfi/bfi_rport.h>
+#include "bfa_intr_priv.h"
+
+BFA_TRC_FILE(HAL, RPORT);
+BFA_MODULE(rport);
+
+#define bfa_rport_offline_cb(__rp) do { \
+ if ((__rp)->bfa->fcs) \
+ bfa_cb_rport_offline((__rp)->rport_drv); \
+ else { \
+ bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \
+ __bfa_cb_rport_offline, (__rp)); \
+ } \
+} while (0)
+
+#define bfa_rport_online_cb(__rp) do { \
+ if ((__rp)->bfa->fcs) \
+ bfa_cb_rport_online((__rp)->rport_drv); \
+ else { \
+ bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \
+ __bfa_cb_rport_online, (__rp)); \
+ } \
+} while (0)
+
+/*
+ * forward declarations
+ */
+static struct bfa_rport_s *bfa_rport_alloc(struct bfa_rport_mod_s *rp_mod);
+static void bfa_rport_free(struct bfa_rport_s *rport);
+static bfa_boolean_t bfa_rport_send_fwcreate(struct bfa_rport_s *rp);
+static bfa_boolean_t bfa_rport_send_fwdelete(struct bfa_rport_s *rp);
+static bfa_boolean_t bfa_rport_send_fwspeed(struct bfa_rport_s *rp);
+static void __bfa_cb_rport_online(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_rport_offline(void *cbarg, bfa_boolean_t complete);
+
+/**
+ * bfa_rport_sm BFA rport state machine
+ */
+
+
+enum bfa_rport_event {
+ BFA_RPORT_SM_CREATE = 1, /* rport create event */
+ BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */
+ BFA_RPORT_SM_ONLINE = 3, /* rport is online */
+ BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */
+ BFA_RPORT_SM_FWRSP = 5, /* firmware response */
+ BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */
+ BFA_RPORT_SM_QOS_SCN = 7, /* QoS SCN from firmware */
+ BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */
+ BFA_RPORT_SM_QRESUME = 9, /* space in requeue queue */
+};
+
+static void bfa_rport_sm_uninit(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_created(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_fwcreate(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_online(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_fwdelete(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_offline(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_deleting(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_offline_pending(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_delete_pending(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_iocdisable(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+static void bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp,
+ enum bfa_rport_event event);
+
+/**
+ * Beginning state, only online event expected.
+ */
+static void
+bfa_rport_sm_uninit(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_CREATE:
+ bfa_stats(rp, sm_un_cr);
+ bfa_sm_set_state(rp, bfa_rport_sm_created);
+ break;
+
+ default:
+ bfa_stats(rp, sm_un_unexp);
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_rport_sm_created(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_ONLINE:
+ bfa_stats(rp, sm_cr_on);
+ if (bfa_rport_send_fwcreate(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_cr_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_cr_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ break;
+
+ default:
+ bfa_stats(rp, sm_cr_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Waiting for rport create response from firmware.
+ */
+static void
+bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_FWRSP:
+ bfa_stats(rp, sm_fwc_rsp);
+ bfa_sm_set_state(rp, bfa_rport_sm_online);
+ bfa_rport_online_cb(rp);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_fwc_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_delete_pending);
+ break;
+
+ case BFA_RPORT_SM_OFFLINE:
+ bfa_stats(rp, sm_fwc_off);
+ bfa_sm_set_state(rp, bfa_rport_sm_offline_pending);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_fwc_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ break;
+
+ default:
+ bfa_stats(rp, sm_fwc_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Request queue is full, awaiting queue resume to send create request.
+ */
+static void
+bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_QRESUME:
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate);
+ bfa_rport_send_fwcreate(rp);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_fwc_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_reqq_wcancel(&rp->reqq_wait);
+ bfa_rport_free(rp);
+ break;
+
+ case BFA_RPORT_SM_OFFLINE:
+ bfa_stats(rp, sm_fwc_off);
+ bfa_sm_set_state(rp, bfa_rport_sm_offline);
+ bfa_reqq_wcancel(&rp->reqq_wait);
+ bfa_rport_offline_cb(rp);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_fwc_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ bfa_reqq_wcancel(&rp->reqq_wait);
+ break;
+
+ default:
+ bfa_stats(rp, sm_fwc_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Online state - normal parking state.
+ */
+static void
+bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ struct bfi_rport_qos_scn_s *qos_scn;
+
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_OFFLINE:
+ bfa_stats(rp, sm_on_off);
+ if (bfa_rport_send_fwdelete(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_fwdelete);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_on_del);
+ if (bfa_rport_send_fwdelete(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_on_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ break;
+
+ case BFA_RPORT_SM_SET_SPEED:
+ bfa_rport_send_fwspeed(rp);
+ break;
+
+ case BFA_RPORT_SM_QOS_SCN:
+ qos_scn = (struct bfi_rport_qos_scn_s *) rp->event_arg.fw_msg;
+ rp->qos_attr = qos_scn->new_qos_attr;
+ bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_flow_id);
+ bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_flow_id);
+ bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_priority);
+ bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_priority);
+
+ qos_scn->old_qos_attr.qos_flow_id =
+ bfa_os_ntohl(qos_scn->old_qos_attr.qos_flow_id);
+ qos_scn->new_qos_attr.qos_flow_id =
+ bfa_os_ntohl(qos_scn->new_qos_attr.qos_flow_id);
+ qos_scn->old_qos_attr.qos_priority =
+ bfa_os_ntohl(qos_scn->old_qos_attr.qos_priority);
+ qos_scn->new_qos_attr.qos_priority =
+ bfa_os_ntohl(qos_scn->new_qos_attr.qos_priority);
+
+ if (qos_scn->old_qos_attr.qos_flow_id !=
+ qos_scn->new_qos_attr.qos_flow_id)
+ bfa_cb_rport_qos_scn_flowid(rp->rport_drv,
+ qos_scn->old_qos_attr,
+ qos_scn->new_qos_attr);
+ if (qos_scn->old_qos_attr.qos_priority !=
+ qos_scn->new_qos_attr.qos_priority)
+ bfa_cb_rport_qos_scn_prio(rp->rport_drv,
+ qos_scn->old_qos_attr,
+ qos_scn->new_qos_attr);
+ break;
+
+ default:
+ bfa_stats(rp, sm_on_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Firmware rport is being deleted - awaiting f/w response.
+ */
+static void
+bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_FWRSP:
+ bfa_stats(rp, sm_fwd_rsp);
+ bfa_sm_set_state(rp, bfa_rport_sm_offline);
+ bfa_rport_offline_cb(rp);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_fwd_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_fwd_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ bfa_rport_offline_cb(rp);
+ break;
+
+ default:
+ bfa_stats(rp, sm_fwd_unexp);
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_QRESUME:
+ bfa_sm_set_state(rp, bfa_rport_sm_fwdelete);
+ bfa_rport_send_fwdelete(rp);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_fwd_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_fwd_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ bfa_reqq_wcancel(&rp->reqq_wait);
+ bfa_rport_offline_cb(rp);
+ break;
+
+ default:
+ bfa_stats(rp, sm_fwd_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Offline state.
+ */
+static void
+bfa_rport_sm_offline(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_off_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ case BFA_RPORT_SM_ONLINE:
+ bfa_stats(rp, sm_off_on);
+ if (bfa_rport_send_fwcreate(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_off_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ break;
+
+ default:
+ bfa_stats(rp, sm_off_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is deleted, waiting for firmware response to delete.
+ */
+static void
+bfa_rport_sm_deleting(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_FWRSP:
+ bfa_stats(rp, sm_del_fwrsp);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_del_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_QRESUME:
+ bfa_stats(rp, sm_del_fwrsp);
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting);
+ bfa_rport_send_fwdelete(rp);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_del_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_reqq_wcancel(&rp->reqq_wait);
+ bfa_rport_free(rp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Waiting for rport create response from firmware. A delete is pending.
+ */
+static void
+bfa_rport_sm_delete_pending(struct bfa_rport_s *rp,
+ enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_FWRSP:
+ bfa_stats(rp, sm_delp_fwrsp);
+ if (bfa_rport_send_fwdelete(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_delp_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ default:
+ bfa_stats(rp, sm_delp_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Waiting for rport create response from firmware. Rport offline is pending.
+ */
+static void
+bfa_rport_sm_offline_pending(struct bfa_rport_s *rp,
+ enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_FWRSP:
+ bfa_stats(rp, sm_offp_fwrsp);
+ if (bfa_rport_send_fwdelete(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_fwdelete);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_offp_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_delete_pending);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ bfa_stats(rp, sm_offp_hwf);
+ bfa_sm_set_state(rp, bfa_rport_sm_iocdisable);
+ break;
+
+ default:
+ bfa_stats(rp, sm_offp_unexp);
+ bfa_assert(0);
+ }
+}
+
+/**
+ * IOC h/w failed.
+ */
+static void
+bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, enum bfa_rport_event event)
+{
+ bfa_trc(rp->bfa, rp->rport_tag);
+ bfa_trc(rp->bfa, event);
+
+ switch (event) {
+ case BFA_RPORT_SM_OFFLINE:
+ bfa_stats(rp, sm_iocd_off);
+ bfa_rport_offline_cb(rp);
+ break;
+
+ case BFA_RPORT_SM_DELETE:
+ bfa_stats(rp, sm_iocd_del);
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+ bfa_rport_free(rp);
+ break;
+
+ case BFA_RPORT_SM_ONLINE:
+ bfa_stats(rp, sm_iocd_on);
+ if (bfa_rport_send_fwcreate(rp))
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate);
+ else
+ bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull);
+ break;
+
+ case BFA_RPORT_SM_HWFAIL:
+ break;
+
+ default:
+ bfa_stats(rp, sm_iocd_unexp);
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_rport_private BFA rport private functions
+ */
+
+static void
+__bfa_cb_rport_online(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_rport_s *rp = cbarg;
+
+ if (complete)
+ bfa_cb_rport_online(rp->rport_drv);
+}
+
+static void
+__bfa_cb_rport_offline(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_rport_s *rp = cbarg;
+
+ if (complete)
+ bfa_cb_rport_offline(rp->rport_drv);
+}
+
+static void
+bfa_rport_qresume(void *cbarg)
+{
+ struct bfa_rport_s *rp = cbarg;
+
+ bfa_sm_send_event(rp, BFA_RPORT_SM_QRESUME);
+}
+
+static void
+bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len)
+{
+ if (cfg->fwcfg.num_rports < BFA_RPORT_MIN)
+ cfg->fwcfg.num_rports = BFA_RPORT_MIN;
+
+ *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s);
+}
+
+static void
+bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa);
+ struct bfa_rport_s *rp;
+ u16 i;
+
+ INIT_LIST_HEAD(&mod->rp_free_q);
+ INIT_LIST_HEAD(&mod->rp_active_q);
+
+ rp = (struct bfa_rport_s *) bfa_meminfo_kva(meminfo);
+ mod->rps_list = rp;
+ mod->num_rports = cfg->fwcfg.num_rports;
+
+ bfa_assert(mod->num_rports
+ && !(mod->num_rports & (mod->num_rports - 1)));
+
+ for (i = 0; i < mod->num_rports; i++, rp++) {
+ bfa_os_memset(rp, 0, sizeof(struct bfa_rport_s));
+ rp->bfa = bfa;
+ rp->rport_tag = i;
+ bfa_sm_set_state(rp, bfa_rport_sm_uninit);
+
+ /**
+ * - is unused
+ */
+ if (i)
+ list_add_tail(&rp->qe, &mod->rp_free_q);
+
+ bfa_reqq_winit(&rp->reqq_wait, bfa_rport_qresume, rp);
+ }
+
+ /**
+ * consume memory
+ */
+ bfa_meminfo_kva(meminfo) = (u8 *) rp;
+}
+
+static void
+bfa_rport_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_rport_detach(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_rport_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_rport_stop(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_rport_iocdisable(struct bfa_s *bfa)
+{
+ struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa);
+ struct bfa_rport_s *rport;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &mod->rp_active_q) {
+ rport = (struct bfa_rport_s *) qe;
+ bfa_sm_send_event(rport, BFA_RPORT_SM_HWFAIL);
+ }
+}
+
+static struct bfa_rport_s *
+bfa_rport_alloc(struct bfa_rport_mod_s *mod)
+{
+ struct bfa_rport_s *rport;
+
+ bfa_q_deq(&mod->rp_free_q, &rport);
+ if (rport)
+ list_add_tail(&rport->qe, &mod->rp_active_q);
+
+ return rport;
+}
+
+static void
+bfa_rport_free(struct bfa_rport_s *rport)
+{
+ struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(rport->bfa);
+
+ bfa_assert(bfa_q_is_on_q(&mod->rp_active_q, rport));
+ list_del(&rport->qe);
+ list_add_tail(&rport->qe, &mod->rp_free_q);
+}
+
+static bfa_boolean_t
+bfa_rport_send_fwcreate(struct bfa_rport_s *rp)
+{
+ struct bfi_rport_create_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
+ if (!m) {
+ bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_CREATE_REQ,
+ bfa_lpuid(rp->bfa));
+ m->bfa_handle = rp->rport_tag;
+ m->max_frmsz = bfa_os_htons(rp->rport_info.max_frmsz);
+ m->pid = rp->rport_info.pid;
+ m->lp_tag = rp->rport_info.lp_tag;
+ m->local_pid = rp->rport_info.local_pid;
+ m->fc_class = rp->rport_info.fc_class;
+ m->vf_en = rp->rport_info.vf_en;
+ m->vf_id = rp->rport_info.vf_id;
+ m->cisc = rp->rport_info.cisc;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
+ return BFA_TRUE;
+}
+
+static bfa_boolean_t
+bfa_rport_send_fwdelete(struct bfa_rport_s *rp)
+{
+ struct bfi_rport_delete_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
+ if (!m) {
+ bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_DELETE_REQ,
+ bfa_lpuid(rp->bfa));
+ m->fw_handle = rp->fw_handle;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
+ return BFA_TRUE;
+}
+
+static bfa_boolean_t
+bfa_rport_send_fwspeed(struct bfa_rport_s *rp)
+{
+ struct bfa_rport_speed_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT);
+ if (!m) {
+ bfa_trc(rp->bfa, rp->rport_info.speed);
+ return BFA_FALSE;
+ }
+
+ bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_SET_SPEED_REQ,
+ bfa_lpuid(rp->bfa));
+ m->fw_handle = rp->fw_handle;
+ m->speed = (u8)rp->rport_info.speed;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT);
+ return BFA_TRUE;
+}
+
+
+
+/**
+ * bfa_rport_public
+ */
+
+/**
+ * Rport interrupt processing.
+ */
+void
+bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ union bfi_rport_i2h_msg_u msg;
+ struct bfa_rport_s *rp;
+
+ bfa_trc(bfa, m->mhdr.msg_id);
+
+ msg.msg = m;
+
+ switch (m->mhdr.msg_id) {
+ case BFI_RPORT_I2H_CREATE_RSP:
+ rp = BFA_RPORT_FROM_TAG(bfa, msg.create_rsp->bfa_handle);
+ rp->fw_handle = msg.create_rsp->fw_handle;
+ rp->qos_attr = msg.create_rsp->qos_attr;
+ bfa_assert(msg.create_rsp->status == BFA_STATUS_OK);
+ bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
+ break;
+
+ case BFI_RPORT_I2H_DELETE_RSP:
+ rp = BFA_RPORT_FROM_TAG(bfa, msg.delete_rsp->bfa_handle);
+ bfa_assert(msg.delete_rsp->status == BFA_STATUS_OK);
+ bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP);
+ break;
+
+ case BFI_RPORT_I2H_QOS_SCN:
+ rp = BFA_RPORT_FROM_TAG(bfa, msg.qos_scn_evt->bfa_handle);
+ rp->event_arg.fw_msg = msg.qos_scn_evt;
+ bfa_sm_send_event(rp, BFA_RPORT_SM_QOS_SCN);
+ break;
+
+ default:
+ bfa_trc(bfa, m->mhdr.msg_id);
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_rport_api
+ */
+
+struct bfa_rport_s *
+bfa_rport_create(struct bfa_s *bfa, void *rport_drv)
+{
+ struct bfa_rport_s *rp;
+
+ rp = bfa_rport_alloc(BFA_RPORT_MOD(bfa));
+
+ if (rp == NULL)
+ return NULL;
+
+ rp->bfa = bfa;
+ rp->rport_drv = rport_drv;
+ bfa_rport_clear_stats(rp);
+
+ bfa_assert(bfa_sm_cmp_state(rp, bfa_rport_sm_uninit));
+ bfa_sm_send_event(rp, BFA_RPORT_SM_CREATE);
+
+ return rp;
+}
+
+void
+bfa_rport_delete(struct bfa_rport_s *rport)
+{
+ bfa_sm_send_event(rport, BFA_RPORT_SM_DELETE);
+}
+
+void
+bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info)
+{
+ bfa_assert(rport_info->max_frmsz != 0);
+
+ /**
+ * Some JBODs are seen to be not setting PDU size correctly in PLOGI
+ * responses. Default to minimum size.
+ */
+ if (rport_info->max_frmsz == 0) {
+ bfa_trc(rport->bfa, rport->rport_tag);
+ rport_info->max_frmsz = FC_MIN_PDUSZ;
+ }
+
+ bfa_os_assign(rport->rport_info, *rport_info);
+ bfa_sm_send_event(rport, BFA_RPORT_SM_ONLINE);
+}
+
+void
+bfa_rport_offline(struct bfa_rport_s *rport)
+{
+ bfa_sm_send_event(rport, BFA_RPORT_SM_OFFLINE);
+}
+
+void
+bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_pport_speed speed)
+{
+ bfa_assert(speed != 0);
+ bfa_assert(speed != BFA_PPORT_SPEED_AUTO);
+
+ rport->rport_info.speed = speed;
+ bfa_sm_send_event(rport, BFA_RPORT_SM_SET_SPEED);
+}
+
+void
+bfa_rport_get_stats(struct bfa_rport_s *rport,
+ struct bfa_rport_hal_stats_s *stats)
+{
+ *stats = rport->stats;
+}
+
+void
+bfa_rport_get_qos_attr(struct bfa_rport_s *rport,
+ struct bfa_rport_qos_attr_s *qos_attr)
+{
+ qos_attr->qos_priority = bfa_os_ntohl(rport->qos_attr.qos_priority);
+ qos_attr->qos_flow_id = bfa_os_ntohl(rport->qos_attr.qos_flow_id);
+
+}
+
+void
+bfa_rport_clear_stats(struct bfa_rport_s *rport)
+{
+ bfa_os_memset(&rport->stats, 0, sizeof(rport->stats));
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_rport_priv.h b/drivers/scsi/bfa/bfa_rport_priv.h
new file mode 100644
index 000000000000..6490ce2e990d
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_rport_priv.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_RPORT_PRIV_H__
+#define __BFA_RPORT_PRIV_H__
+
+#include <bfa_svc.h>
+
+#define BFA_RPORT_MIN 4
+
+struct bfa_rport_mod_s {
+ struct bfa_rport_s *rps_list; /* list of rports */
+ struct list_head rp_free_q; /* free bfa_rports */
+ struct list_head rp_active_q; /* free bfa_rports */
+ u16 num_rports; /* number of rports */
+};
+
+#define BFA_RPORT_MOD(__bfa) (&(__bfa)->modules.rport_mod)
+
+/**
+ * Convert rport tag to RPORT
+ */
+#define BFA_RPORT_FROM_TAG(__bfa, _tag) \
+ (BFA_RPORT_MOD(__bfa)->rps_list + \
+ ((_tag) & (BFA_RPORT_MOD(__bfa)->num_rports - 1)))
+
+/*
+ * external functions
+ */
+void bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+#endif /* __BFA_RPORT_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_sgpg.c b/drivers/scsi/bfa/bfa_sgpg.c
new file mode 100644
index 000000000000..279d8f9b8907
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_sgpg.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+
+BFA_TRC_FILE(HAL, SGPG);
+BFA_MODULE(sgpg);
+
+/**
+ * bfa_sgpg_mod BFA SGPG Mode module
+ */
+
+/**
+ * Compute and return memory needed by FCP(im) module.
+ */
+static void
+bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len,
+ u32 *dm_len)
+{
+ if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN)
+ cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN;
+
+ *km_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfa_sgpg_s);
+ *dm_len += (cfg->drvcfg.num_sgpgs + 1) * sizeof(struct bfi_sgpg_s);
+}
+
+
+static void
+bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *minfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
+ int i;
+ struct bfa_sgpg_s *hsgpg;
+ struct bfi_sgpg_s *sgpg;
+ u64 align_len;
+
+ union {
+ u64 pa;
+ union bfi_addr_u addr;
+ } sgpg_pa;
+
+ INIT_LIST_HEAD(&mod->sgpg_q);
+ INIT_LIST_HEAD(&mod->sgpg_wait_q);
+
+ bfa_trc(bfa, cfg->drvcfg.num_sgpgs);
+
+ mod->num_sgpgs = cfg->drvcfg.num_sgpgs;
+ mod->sgpg_arr_pa = bfa_meminfo_dma_phys(minfo);
+ align_len = (BFA_SGPG_ROUNDUP(mod->sgpg_arr_pa) - mod->sgpg_arr_pa);
+ mod->sgpg_arr_pa += align_len;
+ mod->hsgpg_arr = (struct bfa_sgpg_s *) (bfa_meminfo_kva(minfo) +
+ align_len);
+ mod->sgpg_arr = (struct bfi_sgpg_s *) (bfa_meminfo_dma_virt(minfo) +
+ align_len);
+
+ hsgpg = mod->hsgpg_arr;
+ sgpg = mod->sgpg_arr;
+ sgpg_pa.pa = mod->sgpg_arr_pa;
+ mod->free_sgpgs = mod->num_sgpgs;
+
+ bfa_assert(!(sgpg_pa.pa & (sizeof(struct bfi_sgpg_s) - 1)));
+
+ for (i = 0; i < mod->num_sgpgs; i++) {
+ bfa_os_memset(hsgpg, 0, sizeof(*hsgpg));
+ bfa_os_memset(sgpg, 0, sizeof(*sgpg));
+
+ hsgpg->sgpg = sgpg;
+ hsgpg->sgpg_pa = sgpg_pa.addr;
+ list_add_tail(&hsgpg->qe, &mod->sgpg_q);
+
+ hsgpg++;
+ sgpg++;
+ sgpg_pa.pa += sizeof(struct bfi_sgpg_s);
+ }
+
+ bfa_meminfo_kva(minfo) = (u8 *) hsgpg;
+ bfa_meminfo_dma_virt(minfo) = (u8 *) sgpg;
+ bfa_meminfo_dma_phys(minfo) = sgpg_pa.pa;
+}
+
+static void
+bfa_sgpg_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_sgpg_detach(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_sgpg_start(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_sgpg_stop(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_sgpg_iocdisable(struct bfa_s *bfa)
+{
+}
+
+
+
+/**
+ * bfa_sgpg_public BFA SGPG public functions
+ */
+
+bfa_status_t
+bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs)
+{
+ struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
+ struct bfa_sgpg_s *hsgpg;
+ int i;
+
+ bfa_trc_fp(bfa, nsgpgs);
+
+ if (mod->free_sgpgs < nsgpgs)
+ return BFA_STATUS_ENOMEM;
+
+ for (i = 0; i < nsgpgs; i++) {
+ bfa_q_deq(&mod->sgpg_q, &hsgpg);
+ bfa_assert(hsgpg);
+ list_add_tail(&hsgpg->qe, sgpg_q);
+ }
+
+ mod->free_sgpgs -= nsgpgs;
+ return BFA_STATUS_OK;
+}
+
+void
+bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg)
+{
+ struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
+ struct bfa_sgpg_wqe_s *wqe;
+
+ bfa_trc_fp(bfa, nsgpg);
+
+ mod->free_sgpgs += nsgpg;
+ bfa_assert(mod->free_sgpgs <= mod->num_sgpgs);
+
+ list_splice_tail_init(sgpg_q, &mod->sgpg_q);
+
+ if (list_empty(&mod->sgpg_wait_q))
+ return;
+
+ /**
+ * satisfy as many waiting requests as possible
+ */
+ do {
+ wqe = bfa_q_first(&mod->sgpg_wait_q);
+ if (mod->free_sgpgs < wqe->nsgpg)
+ nsgpg = mod->free_sgpgs;
+ else
+ nsgpg = wqe->nsgpg;
+ bfa_sgpg_malloc(bfa, &wqe->sgpg_q, nsgpg);
+ wqe->nsgpg -= nsgpg;
+ if (wqe->nsgpg == 0) {
+ list_del(&wqe->qe);
+ wqe->cbfn(wqe->cbarg);
+ }
+ } while (mod->free_sgpgs && !list_empty(&mod->sgpg_wait_q));
+}
+
+void
+bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg)
+{
+ struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
+
+ bfa_assert(nsgpg > 0);
+ bfa_assert(nsgpg > mod->free_sgpgs);
+
+ wqe->nsgpg_total = wqe->nsgpg = nsgpg;
+
+ /**
+ * allocate any left to this one first
+ */
+ if (mod->free_sgpgs) {
+ /**
+ * no one else is waiting for SGPG
+ */
+ bfa_assert(list_empty(&mod->sgpg_wait_q));
+ list_splice_tail_init(&mod->sgpg_q, &wqe->sgpg_q);
+ wqe->nsgpg -= mod->free_sgpgs;
+ mod->free_sgpgs = 0;
+ }
+
+ list_add_tail(&wqe->qe, &mod->sgpg_wait_q);
+}
+
+void
+bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe)
+{
+ struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa);
+
+ bfa_assert(bfa_q_is_on_q(&mod->sgpg_wait_q, wqe));
+ list_del(&wqe->qe);
+
+ if (wqe->nsgpg_total != wqe->nsgpg)
+ bfa_sgpg_mfree(bfa, &wqe->sgpg_q,
+ wqe->nsgpg_total - wqe->nsgpg);
+}
+
+void
+bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg),
+ void *cbarg)
+{
+ INIT_LIST_HEAD(&wqe->sgpg_q);
+ wqe->cbfn = cbfn;
+ wqe->cbarg = cbarg;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_sgpg_priv.h b/drivers/scsi/bfa/bfa_sgpg_priv.h
new file mode 100644
index 000000000000..9c2a8cbe7522
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_sgpg_priv.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * hal_sgpg.h BFA SG page module
+ */
+
+#ifndef __BFA_SGPG_PRIV_H__
+#define __BFA_SGPG_PRIV_H__
+
+#include <cs/bfa_q.h>
+
+#define BFA_SGPG_MIN (16)
+
+/**
+ * Alignment macro for SG page allocation
+ */
+#define BFA_SGPG_ROUNDUP(_l) (((_l) + (sizeof(struct bfi_sgpg_s) - 1)) \
+ & ~(sizeof(struct bfi_sgpg_s) - 1))
+
+struct bfa_sgpg_wqe_s {
+ struct list_head qe; /* queue sg page element */
+ int nsgpg; /* pages to be allocated */
+ int nsgpg_total; /* total pages required */
+ void (*cbfn) (void *cbarg);
+ /* callback function */
+ void *cbarg; /* callback arg */
+ struct list_head sgpg_q; /* queue of alloced sgpgs */
+};
+
+struct bfa_sgpg_s {
+ struct list_head qe; /* queue sg page element */
+ struct bfi_sgpg_s *sgpg; /* va of SG page */
+ union bfi_addr_u sgpg_pa;/* pa of SG page */
+};
+
+/**
+ * Given number of SG elements, BFA_SGPG_NPAGE() returns the number of
+ * SG pages required.
+ */
+#define BFA_SGPG_NPAGE(_nsges) (((_nsges) / BFI_SGPG_DATA_SGES) + 1)
+
+struct bfa_sgpg_mod_s {
+ struct bfa_s *bfa;
+ int num_sgpgs; /* number of SG pages */
+ int free_sgpgs; /* number of free SG pages */
+ struct bfa_sgpg_s *hsgpg_arr; /* BFA SG page array */
+ struct bfi_sgpg_s *sgpg_arr; /* actual SG page array */
+ u64 sgpg_arr_pa; /* SG page array DMA addr */
+ struct list_head sgpg_q; /* queue of free SG pages */
+ struct list_head sgpg_wait_q; /* wait queue for SG pages */
+};
+#define BFA_SGPG_MOD(__bfa) (&(__bfa)->modules.sgpg_mod)
+
+bfa_status_t bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q,
+ int nsgpgs);
+void bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q,
+ int nsgpgs);
+void bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe,
+ void (*cbfn) (void *cbarg), void *cbarg);
+void bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe,
+ int nsgpgs);
+void bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe);
+
+#endif /* __BFA_SGPG_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_sm.c b/drivers/scsi/bfa/bfa_sm.c
new file mode 100644
index 000000000000..5420f4f45e58
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_sm.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfasm.c BFA State machine utility functions
+ */
+
+#include <cs/bfa_sm.h>
+
+/**
+ * cs_sm_api
+ */
+
+int
+bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm)
+{
+ int i = 0;
+
+ while (smt[i].sm && smt[i].sm != sm)
+ i++;
+ return smt[i].state;
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_timer.c b/drivers/scsi/bfa/bfa_timer.c
new file mode 100644
index 000000000000..cb76481f5cb1
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_timer.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa_timer.h>
+#include <cs/bfa_debug.h>
+
+void
+bfa_timer_init(struct bfa_timer_mod_s *mod)
+{
+ INIT_LIST_HEAD(&mod->timer_q);
+}
+
+void
+bfa_timer_beat(struct bfa_timer_mod_s *mod)
+{
+ struct list_head *qh = &mod->timer_q;
+ struct list_head *qe, *qe_next;
+ struct bfa_timer_s *elem;
+ struct list_head timedout_q;
+
+ INIT_LIST_HEAD(&timedout_q);
+
+ qe = bfa_q_next(qh);
+
+ while (qe != qh) {
+ qe_next = bfa_q_next(qe);
+
+ elem = (struct bfa_timer_s *) qe;
+ if (elem->timeout <= BFA_TIMER_FREQ) {
+ elem->timeout = 0;
+ list_del(&elem->qe);
+ list_add_tail(&elem->qe, &timedout_q);
+ } else {
+ elem->timeout -= BFA_TIMER_FREQ;
+ }
+
+ qe = qe_next; /* go to next elem */
+ }
+
+ /*
+ * Pop all the timeout entries
+ */
+ while (!list_empty(&timedout_q)) {
+ bfa_q_deq(&timedout_q, &elem);
+ elem->timercb(elem->arg);
+ }
+}
+
+/**
+ * Should be called with lock protection
+ */
+void
+bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
+ void (*timercb) (void *), void *arg, unsigned int timeout)
+{
+
+ bfa_assert(timercb != NULL);
+ bfa_assert(!bfa_q_is_on_q(&mod->timer_q, timer));
+
+ timer->timeout = timeout;
+ timer->timercb = timercb;
+ timer->arg = arg;
+
+ list_add_tail(&timer->qe, &mod->timer_q);
+}
+
+/**
+ * Should be called with lock protection
+ */
+void
+bfa_timer_stop(struct bfa_timer_s *timer)
+{
+ bfa_assert(!list_empty(&timer->qe));
+
+ list_del(&timer->qe);
+}
diff --git a/drivers/scsi/bfa/bfa_trcmod_priv.h b/drivers/scsi/bfa/bfa_trcmod_priv.h
new file mode 100644
index 000000000000..b3562dce7e9f
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_trcmod_priv.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * hal_trcmod.h BFA trace modules
+ */
+
+#ifndef __BFA_TRCMOD_PRIV_H__
+#define __BFA_TRCMOD_PRIV_H__
+
+#include <cs/bfa_trc.h>
+
+/*
+ * !!! Only append to the enums defined here to avoid any versioning
+ * !!! needed between trace utility and driver version
+ */
+enum {
+ BFA_TRC_HAL_IOC = 1,
+ BFA_TRC_HAL_INTR = 2,
+ BFA_TRC_HAL_FCXP = 3,
+ BFA_TRC_HAL_UF = 4,
+ BFA_TRC_HAL_DIAG = 5,
+ BFA_TRC_HAL_RPORT = 6,
+ BFA_TRC_HAL_FCPIM = 7,
+ BFA_TRC_HAL_IOIM = 8,
+ BFA_TRC_HAL_TSKIM = 9,
+ BFA_TRC_HAL_ITNIM = 10,
+ BFA_TRC_HAL_PPORT = 11,
+ BFA_TRC_HAL_SGPG = 12,
+ BFA_TRC_HAL_FLASH = 13,
+ BFA_TRC_HAL_DEBUG = 14,
+ BFA_TRC_HAL_WWN = 15,
+ BFA_TRC_HAL_FLASH_RAW = 16,
+ BFA_TRC_HAL_SBOOT = 17,
+ BFA_TRC_HAL_SBOOT_IO = 18,
+ BFA_TRC_HAL_SBOOT_INTR = 19,
+ BFA_TRC_HAL_SBTEST = 20,
+ BFA_TRC_HAL_IPFC = 21,
+ BFA_TRC_HAL_IOCFC = 22,
+ BFA_TRC_HAL_FCPTM = 23,
+ BFA_TRC_HAL_IOTM = 24,
+ BFA_TRC_HAL_TSKTM = 25,
+ BFA_TRC_HAL_TIN = 26,
+ BFA_TRC_HAL_LPS = 27,
+ BFA_TRC_HAL_FCDIAG = 28,
+ BFA_TRC_HAL_PBIND = 29,
+ BFA_TRC_HAL_IOCFC_CT = 30,
+ BFA_TRC_HAL_IOCFC_CB = 31,
+ BFA_TRC_HAL_IOCFC_Q = 32,
+};
+
+#endif /* __BFA_TRCMOD_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfa_tskim.c b/drivers/scsi/bfa/bfa_tskim.c
new file mode 100644
index 000000000000..ff7a4dc0bf3c
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_tskim.c
@@ -0,0 +1,690 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <bfa_cb_ioim_macros.h>
+
+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)); \
+ bfa_tskim_notify_comp(__tskim); \
+} while (0)
+
+#define bfa_tskim_notify_comp(__tskim) do { \
+ if ((__tskim)->notify) \
+ bfa_itnim_tskdone((__tskim)->itnim); \
+} while (0)
+
+/*
+ * forward declarations
+ */
+static void __bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete);
+static void __bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete);
+static bfa_boolean_t bfa_tskim_match_scope(struct bfa_tskim_s *tskim,
+ lun_t lun);
+static void bfa_tskim_gather_ios(struct bfa_tskim_s *tskim);
+static void bfa_tskim_cleanp_comp(void *tskim_cbarg);
+static void bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim);
+static bfa_boolean_t bfa_tskim_send(struct bfa_tskim_s *tskim);
+static bfa_boolean_t bfa_tskim_send_abort(struct bfa_tskim_s *tskim);
+static void bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim);
+
+/**
+ * bfa_tskim_sm
+ */
+
+enum bfa_tskim_event {
+ BFA_TSKIM_SM_START = 1, /* TM command start */
+ BFA_TSKIM_SM_DONE = 2, /* TM completion */
+ BFA_TSKIM_SM_QRESUME = 3, /* resume after qfull */
+ BFA_TSKIM_SM_HWFAIL = 5, /* IOC h/w failure event */
+ BFA_TSKIM_SM_HCB = 6, /* BFA callback completion */
+ BFA_TSKIM_SM_IOS_DONE = 7, /* IO and sub TM completions */
+ BFA_TSKIM_SM_CLEANUP = 8, /* TM cleanup on ITN offline */
+ BFA_TSKIM_SM_CLEANUP_DONE = 9, /* TM abort completion */
+};
+
+static void bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_active(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+static void bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event);
+
+/**
+ * Task management command beginning state.
+ */
+static void
+bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_START:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_active);
+ bfa_tskim_gather_ios(tskim);
+
+ /**
+ * If device is offline, do not send TM on wire. Just cleanup
+ * any pending IO requests and complete TM request.
+ */
+ if (!bfa_itnim_is_online(tskim->itnim)) {
+ bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
+ tskim->tsk_status = BFI_TSKIM_STS_OK;
+ bfa_tskim_cleanup_ios(tskim);
+ return;
+ }
+
+ if (!bfa_tskim_send(tskim)) {
+ bfa_sm_set_state(tskim, bfa_tskim_sm_qfull);
+ bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq,
+ &tskim->reqq_wait);
+ }
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * brief
+ * TM command is active, awaiting completion from firmware to
+ * cleanup IO requests in TM scope.
+ */
+static void
+bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_DONE:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
+ bfa_tskim_cleanup_ios(tskim);
+ break;
+
+ case BFA_TSKIM_SM_CLEANUP:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup);
+ if (!bfa_tskim_send_abort(tskim)) {
+ bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup_qfull);
+ bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq,
+ &tskim->reqq_wait);
+ }
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_tskim_iocdisable_ios(tskim);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * An active TM is being cleaned up since ITN is offline. Awaiting cleanup
+ * completion event from firmware.
+ */
+static void
+bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_DONE:
+ /**
+ * Ignore and wait for ABORT completion from firmware.
+ */
+ break;
+
+ case BFA_TSKIM_SM_CLEANUP_DONE:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
+ bfa_tskim_cleanup_ios(tskim);
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_tskim_iocdisable_ios(tskim);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_IOS_DONE:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_done);
+ break;
+
+ case BFA_TSKIM_SM_CLEANUP:
+ /**
+ * Ignore, TM command completed on wire.
+ * Notify TM conmpletion on IO cleanup completion.
+ */
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_tskim_iocdisable_ios(tskim);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Task management command is waiting for room in request CQ
+ */
+static void
+bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_QRESUME:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_active);
+ bfa_tskim_send(tskim);
+ break;
+
+ case BFA_TSKIM_SM_CLEANUP:
+ /**
+ * No need to send TM on wire since ITN is offline.
+ */
+ bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup);
+ bfa_reqq_wcancel(&tskim->reqq_wait);
+ bfa_tskim_cleanup_ios(tskim);
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_reqq_wcancel(&tskim->reqq_wait);
+ bfa_tskim_iocdisable_ios(tskim);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Task management command is active, awaiting for room in request CQ
+ * to send clean up request.
+ */
+static void
+bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim,
+ enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_DONE:
+ bfa_reqq_wcancel(&tskim->reqq_wait);
+ /**
+ *
+ * Fall through !!!
+ */
+
+ case BFA_TSKIM_SM_QRESUME:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup);
+ bfa_tskim_send_abort(tskim);
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_hcb);
+ bfa_reqq_wcancel(&tskim->reqq_wait);
+ bfa_tskim_iocdisable_ios(tskim);
+ bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * BFA callback is pending
+ */
+static void
+bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event)
+{
+ bfa_trc(tskim->bfa, event);
+
+ switch (event) {
+ case BFA_TSKIM_SM_HCB:
+ bfa_sm_set_state(tskim, bfa_tskim_sm_uninit);
+ bfa_tskim_free(tskim);
+ break;
+
+ case BFA_TSKIM_SM_CLEANUP:
+ bfa_tskim_notify_comp(tskim);
+ break;
+
+ case BFA_TSKIM_SM_HWFAIL:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * bfa_tskim_private
+ */
+
+static void
+__bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_tskim_s *tskim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB);
+ return;
+ }
+
+ bfa_stats(tskim->itnim, tm_success);
+ bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk, tskim->tsk_status);
+}
+
+static void
+__bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_tskim_s *tskim = cbarg;
+
+ if (!complete) {
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB);
+ return;
+ }
+
+ bfa_stats(tskim->itnim, tm_failures);
+ bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk,
+ BFI_TSKIM_STS_FAILED);
+}
+
+static bfa_boolean_t
+bfa_tskim_match_scope(struct bfa_tskim_s *tskim, lun_t lun)
+{
+ switch (tskim->tm_cmnd) {
+ case FCP_TM_TARGET_RESET:
+ return BFA_TRUE;
+
+ case FCP_TM_ABORT_TASK_SET:
+ case FCP_TM_CLEAR_TASK_SET:
+ case FCP_TM_LUN_RESET:
+ case FCP_TM_CLEAR_ACA:
+ return (tskim->lun == lun);
+
+ default:
+ bfa_assert(0);
+ }
+
+ return BFA_FALSE;
+}
+
+/**
+ * Gather affected IO requests and task management commands.
+ */
+static void
+bfa_tskim_gather_ios(struct bfa_tskim_s *tskim)
+{
+ struct bfa_itnim_s *itnim = tskim->itnim;
+ struct bfa_ioim_s *ioim;
+ struct list_head *qe, *qen;
+
+ INIT_LIST_HEAD(&tskim->io_q);
+
+ /**
+ * Gather any active IO requests first.
+ */
+ list_for_each_safe(qe, qen, &itnim->io_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ if (bfa_tskim_match_scope
+ (tskim, bfa_cb_ioim_get_lun(ioim->dio))) {
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &tskim->io_q);
+ }
+ }
+
+ /**
+ * Failback any pending IO requests immediately.
+ */
+ list_for_each_safe(qe, qen, &itnim->pending_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ if (bfa_tskim_match_scope
+ (tskim, bfa_cb_ioim_get_lun(ioim->dio))) {
+ list_del(&ioim->qe);
+ list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q);
+ bfa_ioim_tov(ioim);
+ }
+ }
+}
+
+/**
+ * IO cleanup completion
+ */
+static void
+bfa_tskim_cleanp_comp(void *tskim_cbarg)
+{
+ struct bfa_tskim_s *tskim = tskim_cbarg;
+
+ bfa_stats(tskim->itnim, tm_io_comps);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_IOS_DONE);
+}
+
+/**
+ * Gather affected IO requests and task management commands.
+ */
+static void
+bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim)
+{
+ struct bfa_ioim_s *ioim;
+ struct list_head *qe, *qen;
+
+ bfa_wc_init(&tskim->wc, bfa_tskim_cleanp_comp, tskim);
+
+ list_for_each_safe(qe, qen, &tskim->io_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ bfa_wc_up(&tskim->wc);
+ bfa_ioim_cleanup_tm(ioim, tskim);
+ }
+
+ bfa_wc_wait(&tskim->wc);
+}
+
+/**
+ * Send task management request to firmware.
+ */
+static bfa_boolean_t
+bfa_tskim_send(struct bfa_tskim_s *tskim)
+{
+ struct bfa_itnim_s *itnim = tskim->itnim;
+ struct bfi_tskim_req_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(tskim->bfa, itnim->reqq);
+ if (!m)
+ return BFA_FALSE;
+
+ /**
+ * build i/o request message next
+ */
+ bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_TM_REQ,
+ bfa_lpuid(tskim->bfa));
+
+ m->tsk_tag = bfa_os_htons(tskim->tsk_tag);
+ m->itn_fhdl = tskim->itnim->rport->fw_handle;
+ m->t_secs = tskim->tsecs;
+ m->lun = tskim->lun;
+ m->tm_flags = tskim->tm_cmnd;
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(tskim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+/**
+ * Send abort request to cleanup an active TM to firmware.
+ */
+static bfa_boolean_t
+bfa_tskim_send_abort(struct bfa_tskim_s *tskim)
+{
+ struct bfa_itnim_s *itnim = tskim->itnim;
+ struct bfi_tskim_abortreq_s *m;
+
+ /**
+ * check for room in queue to send request now
+ */
+ m = bfa_reqq_next(tskim->bfa, itnim->reqq);
+ if (!m)
+ return BFA_FALSE;
+
+ /**
+ * build i/o request message next
+ */
+ bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_ABORT_REQ,
+ bfa_lpuid(tskim->bfa));
+
+ m->tsk_tag = bfa_os_htons(tskim->tsk_tag);
+
+ /**
+ * queue I/O message to firmware
+ */
+ bfa_reqq_produce(tskim->bfa, itnim->reqq);
+ return BFA_TRUE;
+}
+
+/**
+ * Call to resume task management cmnd waiting for room in request queue.
+ */
+static void
+bfa_tskim_qresume(void *cbarg)
+{
+ struct bfa_tskim_s *tskim = cbarg;
+
+ bfa_fcpim_stats(tskim->fcpim, qresumes);
+ bfa_stats(tskim->itnim, tm_qresumes);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_QRESUME);
+}
+
+/**
+ * Cleanup IOs associated with a task mangement command on IOC failures.
+ */
+static void
+bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim)
+{
+ struct bfa_ioim_s *ioim;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &tskim->io_q) {
+ ioim = (struct bfa_ioim_s *) qe;
+ bfa_ioim_iocdisable(ioim);
+ }
+}
+
+
+
+/**
+ * bfa_tskim_friend
+ */
+
+/**
+ * Notification on completions from related ioim.
+ */
+void
+bfa_tskim_iodone(struct bfa_tskim_s *tskim)
+{
+ bfa_wc_down(&tskim->wc);
+}
+
+/**
+ * Handle IOC h/w failure notification from itnim.
+ */
+void
+bfa_tskim_iocdisable(struct bfa_tskim_s *tskim)
+{
+ tskim->notify = BFA_FALSE;
+ bfa_stats(tskim->itnim, tm_iocdowns);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_HWFAIL);
+}
+
+/**
+ * Cleanup TM command and associated IOs as part of ITNIM offline.
+ */
+void
+bfa_tskim_cleanup(struct bfa_tskim_s *tskim)
+{
+ tskim->notify = BFA_TRUE;
+ bfa_stats(tskim->itnim, tm_cleanups);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP);
+}
+
+/**
+ * Memory allocation and initialization.
+ */
+void
+bfa_tskim_attach(struct bfa_fcpim_mod_s *fcpim, struct bfa_meminfo_s *minfo)
+{
+ struct bfa_tskim_s *tskim;
+ u16 i;
+
+ INIT_LIST_HEAD(&fcpim->tskim_free_q);
+
+ tskim = (struct bfa_tskim_s *) bfa_meminfo_kva(minfo);
+ fcpim->tskim_arr = tskim;
+
+ for (i = 0; i < fcpim->num_tskim_reqs; i++, tskim++) {
+ /*
+ * initialize TSKIM
+ */
+ bfa_os_memset(tskim, 0, sizeof(struct bfa_tskim_s));
+ tskim->tsk_tag = i;
+ tskim->bfa = fcpim->bfa;
+ tskim->fcpim = fcpim;
+ tskim->notify = BFA_FALSE;
+ bfa_reqq_winit(&tskim->reqq_wait, bfa_tskim_qresume,
+ tskim);
+ bfa_sm_set_state(tskim, bfa_tskim_sm_uninit);
+
+ list_add_tail(&tskim->qe, &fcpim->tskim_free_q);
+ }
+
+ bfa_meminfo_kva(minfo) = (u8 *) tskim;
+}
+
+void
+bfa_tskim_detach(struct bfa_fcpim_mod_s *fcpim)
+{
+ /**
+ * @todo
+ */
+}
+
+void
+bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfi_tskim_rsp_s *rsp = (struct bfi_tskim_rsp_s *) m;
+ struct bfa_tskim_s *tskim;
+ u16 tsk_tag = bfa_os_ntohs(rsp->tsk_tag);
+
+ tskim = BFA_TSKIM_FROM_TAG(fcpim, tsk_tag);
+ bfa_assert(tskim->tsk_tag == tsk_tag);
+
+ tskim->tsk_status = rsp->tsk_status;
+
+ /**
+ * Firmware sends BFI_TSKIM_STS_ABORTED status for abort
+ * requests. All other statuses are for normal completions.
+ */
+ if (rsp->tsk_status == BFI_TSKIM_STS_ABORTED) {
+ bfa_stats(tskim->itnim, tm_cleanup_comps);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP_DONE);
+ } else {
+ bfa_stats(tskim->itnim, tm_fw_rsps);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_DONE);
+ }
+}
+
+
+
+/**
+ * bfa_tskim_api
+ */
+
+
+struct bfa_tskim_s *
+bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk)
+{
+ struct bfa_fcpim_mod_s *fcpim = BFA_FCPIM_MOD(bfa);
+ struct bfa_tskim_s *tskim;
+
+ bfa_q_deq(&fcpim->tskim_free_q, &tskim);
+
+ if (!tskim)
+ bfa_fcpim_stats(fcpim, no_tskims);
+ else
+ tskim->dtsk = dtsk;
+
+ return tskim;
+}
+
+void
+bfa_tskim_free(struct bfa_tskim_s *tskim)
+{
+ bfa_assert(bfa_q_is_on_q_func(&tskim->itnim->tsk_q, &tskim->qe));
+ list_del(&tskim->qe);
+ list_add_tail(&tskim->qe, &tskim->fcpim->tskim_free_q);
+}
+
+/**
+ * Start a task management command.
+ *
+ * @param[in] tskim BFA task management command instance
+ * @param[in] itnim i-t nexus for the task management command
+ * @param[in] lun lun, if applicable
+ * @param[in] tm_cmnd Task management command code.
+ * @param[in] t_secs Timeout in seconds
+ *
+ * @return None.
+ */
+void
+bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim, lun_t lun,
+ enum fcp_tm_cmnd tm_cmnd, u8 tsecs)
+{
+ tskim->itnim = itnim;
+ tskim->lun = lun;
+ tskim->tm_cmnd = tm_cmnd;
+ tskim->tsecs = tsecs;
+ tskim->notify = BFA_FALSE;
+ bfa_stats(itnim, tm_cmnds);
+
+ list_add_tail(&tskim->qe, &itnim->tsk_q);
+ bfa_sm_send_event(tskim, BFA_TSKIM_SM_START);
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_uf.c b/drivers/scsi/bfa/bfa_uf.c
new file mode 100644
index 000000000000..4b3c2417d180
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_uf.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_uf.c BFA unsolicited frame receive implementation
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_uf.h>
+#include <cs/bfa_debug.h>
+
+BFA_TRC_FILE(HAL, UF);
+BFA_MODULE(uf);
+
+/*
+ *****************************************************************************
+ * Internal functions
+ *****************************************************************************
+ */
+static void
+__bfa_cb_uf_recv(void *cbarg, bfa_boolean_t complete)
+{
+ struct bfa_uf_s *uf = cbarg;
+ struct bfa_uf_mod_s *ufm = BFA_UF_MOD(uf->bfa);
+
+ if (complete)
+ ufm->ufrecv(ufm->cbarg, uf);
+}
+
+static void
+claim_uf_pbs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
+{
+ u32 uf_pb_tot_sz;
+
+ ufm->uf_pbs_kva = (struct bfa_uf_buf_s *) bfa_meminfo_dma_virt(mi);
+ ufm->uf_pbs_pa = bfa_meminfo_dma_phys(mi);
+ uf_pb_tot_sz = BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * ufm->num_ufs),
+ BFA_DMA_ALIGN_SZ);
+
+ bfa_meminfo_dma_virt(mi) += uf_pb_tot_sz;
+ bfa_meminfo_dma_phys(mi) += uf_pb_tot_sz;
+
+ bfa_os_memset((void *)ufm->uf_pbs_kva, 0, uf_pb_tot_sz);
+}
+
+static void
+claim_uf_post_msgs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
+{
+ struct bfi_uf_buf_post_s *uf_bp_msg;
+ struct bfi_sge_s *sge;
+ union bfi_addr_u sga_zero = { {0} };
+ u16 i;
+ u16 buf_len;
+
+ ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_meminfo_kva(mi);
+ uf_bp_msg = ufm->uf_buf_posts;
+
+ for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs;
+ i++, uf_bp_msg++) {
+ bfa_os_memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s));
+
+ uf_bp_msg->buf_tag = i;
+ buf_len = sizeof(struct bfa_uf_buf_s);
+ uf_bp_msg->buf_len = bfa_os_htons(buf_len);
+ bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST,
+ bfa_lpuid(ufm->bfa));
+
+ sge = uf_bp_msg->sge;
+ sge[0].sg_len = buf_len;
+ sge[0].flags = BFI_SGE_DATA_LAST;
+ bfa_dma_addr_set(sge[0].sga, ufm_pbs_pa(ufm, i));
+ bfa_sge_to_be(sge);
+
+ sge[1].sg_len = buf_len;
+ sge[1].flags = BFI_SGE_PGDLEN;
+ sge[1].sga = sga_zero;
+ bfa_sge_to_be(&sge[1]);
+ }
+
+ /**
+ * advance pointer beyond consumed memory
+ */
+ bfa_meminfo_kva(mi) = (u8 *) uf_bp_msg;
+}
+
+static void
+claim_ufs(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
+{
+ u16 i;
+ struct bfa_uf_s *uf;
+
+ /*
+ * Claim block of memory for UF list
+ */
+ ufm->uf_list = (struct bfa_uf_s *) bfa_meminfo_kva(mi);
+
+ /*
+ * Initialize UFs and queue it in UF free queue
+ */
+ for (i = 0, uf = ufm->uf_list; i < ufm->num_ufs; i++, uf++) {
+ bfa_os_memset(uf, 0, sizeof(struct bfa_uf_s));
+ uf->bfa = ufm->bfa;
+ uf->uf_tag = i;
+ uf->pb_len = sizeof(struct bfa_uf_buf_s);
+ uf->buf_kva = (void *)&ufm->uf_pbs_kva[i];
+ uf->buf_pa = ufm_pbs_pa(ufm, i);
+ list_add_tail(&uf->qe, &ufm->uf_free_q);
+ }
+
+ /**
+ * advance memory pointer
+ */
+ bfa_meminfo_kva(mi) = (u8 *) uf;
+}
+
+static void
+uf_mem_claim(struct bfa_uf_mod_s *ufm, struct bfa_meminfo_s *mi)
+{
+ claim_uf_pbs(ufm, mi);
+ claim_ufs(ufm, mi);
+ claim_uf_post_msgs(ufm, mi);
+}
+
+static void
+bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *ndm_len, u32 *dm_len)
+{
+ u32 num_ufs = cfg->fwcfg.num_uf_bufs;
+
+ /*
+ * dma-able memory for UF posted bufs
+ */
+ *dm_len += BFA_ROUNDUP((sizeof(struct bfa_uf_buf_s) * num_ufs),
+ BFA_DMA_ALIGN_SZ);
+
+ /*
+ * kernel Virtual memory for UFs and UF buf post msg copies
+ */
+ *ndm_len += sizeof(struct bfa_uf_s) * num_ufs;
+ *ndm_len += sizeof(struct bfi_uf_buf_post_s) * num_ufs;
+}
+
+static void
+bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev)
+{
+ struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
+
+ bfa_os_memset(ufm, 0, sizeof(struct bfa_uf_mod_s));
+ ufm->bfa = bfa;
+ ufm->num_ufs = cfg->fwcfg.num_uf_bufs;
+ INIT_LIST_HEAD(&ufm->uf_free_q);
+ INIT_LIST_HEAD(&ufm->uf_posted_q);
+
+ uf_mem_claim(ufm, meminfo);
+}
+
+static void
+bfa_uf_initdone(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_uf_detach(struct bfa_s *bfa)
+{
+}
+
+static struct bfa_uf_s *
+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;
+}
+
+static void
+bfa_uf_put(struct bfa_uf_mod_s *uf_mod, struct bfa_uf_s *uf)
+{
+ list_add_tail(&uf->qe, &uf_mod->uf_free_q);
+}
+
+static bfa_status_t
+bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf)
+{
+ struct bfi_uf_buf_post_s *uf_post_msg;
+
+ uf_post_msg = bfa_reqq_next(ufm->bfa, BFA_REQQ_FCXP);
+ if (!uf_post_msg)
+ return BFA_STATUS_FAILED;
+
+ bfa_os_memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag],
+ sizeof(struct bfi_uf_buf_post_s));
+ bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP);
+
+ bfa_trc(ufm->bfa, uf->uf_tag);
+
+ list_add_tail(&uf->qe, &ufm->uf_posted_q);
+ return BFA_STATUS_OK;
+}
+
+static void
+bfa_uf_post_all(struct bfa_uf_mod_s *uf_mod)
+{
+ struct bfa_uf_s *uf;
+
+ while ((uf = bfa_uf_get(uf_mod)) != NULL) {
+ if (bfa_uf_post(uf_mod, uf) != BFA_STATUS_OK)
+ break;
+ }
+}
+
+static void
+uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m)
+{
+ struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
+ u16 uf_tag = m->buf_tag;
+ struct bfa_uf_buf_s *uf_buf = &ufm->uf_pbs_kva[uf_tag];
+ struct bfa_uf_s *uf = &ufm->uf_list[uf_tag];
+ u8 *buf = &uf_buf->d[0];
+ struct fchs_s *fchs;
+
+ m->frm_len = bfa_os_ntohs(m->frm_len);
+ m->xfr_len = bfa_os_ntohs(m->xfr_len);
+
+ fchs = (struct fchs_s *) uf_buf;
+
+ list_del(&uf->qe); /* dequeue from posted queue */
+
+ uf->data_ptr = buf;
+ uf->data_len = m->xfr_len;
+
+ bfa_assert(uf->data_len >= sizeof(struct fchs_s));
+
+ if (uf->data_len == sizeof(struct fchs_s)) {
+ bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_UF, BFA_PL_EID_RX,
+ uf->data_len, (struct fchs_s *) buf);
+ } else {
+ u32 pld_w0 = *((u32 *) (buf + sizeof(struct fchs_s)));
+ bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_UF,
+ BFA_PL_EID_RX, uf->data_len,
+ (struct fchs_s *) buf, pld_w0);
+ }
+
+ bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf);
+}
+
+static void
+bfa_uf_stop(struct bfa_s *bfa)
+{
+}
+
+static void
+bfa_uf_iocdisable(struct bfa_s *bfa)
+{
+ struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
+ struct bfa_uf_s *uf;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &ufm->uf_posted_q) {
+ uf = (struct bfa_uf_s *) qe;
+ list_del(&uf->qe);
+ bfa_uf_put(ufm, uf);
+ }
+}
+
+static void
+bfa_uf_start(struct bfa_s *bfa)
+{
+ bfa_uf_post_all(BFA_UF_MOD(bfa));
+}
+
+
+
+/**
+ * bfa_uf_api
+ */
+
+/**
+ * Register handler for all unsolicted recieve frames.
+ *
+ * @param[in] bfa BFA instance
+ * @param[in] ufrecv receive handler function
+ * @param[in] cbarg receive handler arg
+ */
+void
+bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, void *cbarg)
+{
+ struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa);
+
+ ufm->ufrecv = ufrecv;
+ ufm->cbarg = cbarg;
+}
+
+/**
+ * Free an unsolicited frame back to BFA.
+ *
+ * @param[in] uf unsolicited frame to be freed
+ *
+ * @return None
+ */
+void
+bfa_uf_free(struct bfa_uf_s *uf)
+{
+ bfa_uf_put(BFA_UF_MOD(uf->bfa), uf);
+ bfa_uf_post_all(BFA_UF_MOD(uf->bfa));
+}
+
+
+
+/**
+ * uf_pub BFA uf module public functions
+ */
+
+void
+bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg)
+{
+ bfa_trc(bfa, msg->mhdr.msg_id);
+
+ switch (msg->mhdr.msg_id) {
+ case BFI_UF_I2H_FRM_RCVD:
+ uf_recv(bfa, (struct bfi_uf_frm_rcvd_s *) msg);
+ break;
+
+ default:
+ bfa_trc(bfa, msg->mhdr.msg_id);
+ bfa_assert(0);
+ }
+}
+
+
diff --git a/drivers/scsi/bfa/bfa_uf_priv.h b/drivers/scsi/bfa/bfa_uf_priv.h
new file mode 100644
index 000000000000..bcb490f834f3
--- /dev/null
+++ b/drivers/scsi/bfa/bfa_uf_priv.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_UF_PRIV_H__
+#define __BFA_UF_PRIV_H__
+
+#include <cs/bfa_sm.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_uf.h>
+
+#define BFA_UF_MIN (4)
+
+struct bfa_uf_mod_s {
+ struct bfa_s *bfa; /* back pointer to BFA */
+ struct bfa_uf_s *uf_list; /* array of UFs */
+ u16 num_ufs; /* num unsolicited rx frames */
+ struct list_head uf_free_q; /* free UFs */
+ struct list_head uf_posted_q; /* UFs posted to IOC */
+ struct bfa_uf_buf_s *uf_pbs_kva; /* list UF bufs request pld */
+ u64 uf_pbs_pa; /* phy addr for UF bufs */
+ struct bfi_uf_buf_post_s *uf_buf_posts;
+ /* pre-built UF post msgs */
+ bfa_cb_uf_recv_t ufrecv; /* uf recv handler function */
+ void *cbarg; /* uf receive handler arg */
+};
+
+#define BFA_UF_MOD(__bfa) (&(__bfa)->modules.uf_mod)
+
+#define ufm_pbs_pa(_ufmod, _uftag) \
+ ((_ufmod)->uf_pbs_pa + sizeof(struct bfa_uf_buf_s) * (_uftag))
+
+void bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg);
+
+#endif /* __BFA_UF_PRIV_H__ */
diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c
new file mode 100644
index 000000000000..b52b773d49d9
--- /dev/null
+++ b/drivers/scsi/bfa/bfad.c
@@ -0,0 +1,1182 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfad.c Linux driver PCI interface module.
+ */
+
+#include <linux/module.h>
+#include "bfad_drv.h"
+#include "bfad_im.h"
+#include "bfad_tm.h"
+#include "bfad_ipfc.h"
+#include "bfad_trcmod.h"
+#include <fcb/bfa_fcb_vf.h>
+#include <fcb/bfa_fcb_rport.h>
+#include <fcb/bfa_fcb_port.h>
+#include <fcb/bfa_fcb.h>
+
+BFA_TRC_FILE(LDRV, BFAD);
+static DEFINE_MUTEX(bfad_mutex);
+LIST_HEAD(bfad_list);
+static int bfad_inst;
+int bfad_supported_fc4s;
+
+static char *host_name;
+static char *os_name;
+static char *os_patch;
+static int num_rports;
+static int num_ios;
+static int num_tms;
+static int num_fcxps;
+static int num_ufbufs;
+static int reqq_size;
+static int rspq_size;
+static int num_sgpgs;
+static int rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT;
+static int bfa_io_max_sge = BFAD_IO_MAX_SGE;
+static int log_level = BFA_LOG_WARNING;
+static int ioc_auto_recover = BFA_TRUE;
+static int ipfc_enable = BFA_FALSE;
+static int ipfc_mtu = -1;
+int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH;
+int bfa_linkup_delay = -1;
+
+module_param(os_name, charp, S_IRUGO | S_IWUSR);
+module_param(os_patch, charp, S_IRUGO | S_IWUSR);
+module_param(host_name, charp, S_IRUGO | S_IWUSR);
+module_param(num_rports, int, S_IRUGO | S_IWUSR);
+module_param(num_ios, int, S_IRUGO | S_IWUSR);
+module_param(num_tms, int, S_IRUGO | S_IWUSR);
+module_param(num_fcxps, int, S_IRUGO | S_IWUSR);
+module_param(num_ufbufs, int, S_IRUGO | S_IWUSR);
+module_param(reqq_size, int, S_IRUGO | S_IWUSR);
+module_param(rspq_size, int, S_IRUGO | S_IWUSR);
+module_param(num_sgpgs, int, S_IRUGO | S_IWUSR);
+module_param(rport_del_timeout, int, S_IRUGO | S_IWUSR);
+module_param(bfa_lun_queue_depth, int, S_IRUGO | S_IWUSR);
+module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR);
+module_param(log_level, int, S_IRUGO | S_IWUSR);
+module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR);
+module_param(ipfc_enable, int, S_IRUGO | S_IWUSR);
+module_param(ipfc_mtu, int, S_IRUGO | S_IWUSR);
+module_param(bfa_linkup_delay, int, S_IRUGO | S_IWUSR);
+
+/*
+ * Stores the module parm num_sgpgs value;
+ * used to reset for bfad next instance.
+ */
+static int num_sgpgs_parm;
+
+static bfa_status_t
+bfad_fc4_probe(struct bfad_s *bfad)
+{
+ int rc;
+
+ rc = bfad_im_probe(bfad);
+ if (rc != BFA_STATUS_OK)
+ goto ext;
+
+ bfad_tm_probe(bfad);
+
+ if (ipfc_enable)
+ bfad_ipfc_probe(bfad);
+ext:
+ return rc;
+}
+
+static void
+bfad_fc4_probe_undo(struct bfad_s *bfad)
+{
+ bfad_im_probe_undo(bfad);
+ bfad_tm_probe_undo(bfad);
+ if (ipfc_enable)
+ bfad_ipfc_probe_undo(bfad);
+}
+
+static void
+bfad_fc4_probe_post(struct bfad_s *bfad)
+{
+ if (bfad->im)
+ bfad_im_probe_post(bfad->im);
+
+ bfad_tm_probe_post(bfad);
+ if (ipfc_enable)
+ bfad_ipfc_probe_post(bfad);
+}
+
+static bfa_status_t
+bfad_fc4_port_new(struct bfad_s *bfad, struct bfad_port_s *port, int roles)
+{
+ int rc = BFA_STATUS_FAILED;
+
+ if (roles & BFA_PORT_ROLE_FCP_IM)
+ rc = bfad_im_port_new(bfad, port);
+ if (rc != BFA_STATUS_OK)
+ goto ext;
+
+ if (roles & BFA_PORT_ROLE_FCP_TM)
+ rc = bfad_tm_port_new(bfad, port);
+ if (rc != BFA_STATUS_OK)
+ goto ext;
+
+ if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable)
+ rc = bfad_ipfc_port_new(bfad, port, port->pvb_type);
+ext:
+ return rc;
+}
+
+static void
+bfad_fc4_port_delete(struct bfad_s *bfad, struct bfad_port_s *port, int roles)
+{
+ if (roles & BFA_PORT_ROLE_FCP_IM)
+ bfad_im_port_delete(bfad, port);
+
+ if (roles & BFA_PORT_ROLE_FCP_TM)
+ bfad_tm_port_delete(bfad, port);
+
+ if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable)
+ bfad_ipfc_port_delete(bfad, port);
+}
+
+/**
+ * BFA callbacks
+ */
+void
+bfad_hcb_comp(void *arg, bfa_status_t status)
+{
+ struct bfad_hal_comp *fcomp = (struct bfad_hal_comp *)arg;
+
+ fcomp->status = status;
+ complete(&fcomp->comp);
+}
+
+/**
+ * bfa_init callback
+ */
+void
+bfa_cb_init(void *drv, bfa_status_t init_status)
+{
+ struct bfad_s *bfad = drv;
+
+ if (init_status == BFA_STATUS_OK)
+ bfad->bfad_flags |= BFAD_HAL_INIT_DONE;
+
+ complete(&bfad->comp);
+}
+
+
+
+/**
+ * BFA_FCS callbacks
+ */
+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));
+}
+
+struct bfad_port_s *
+bfa_fcb_port_new(struct bfad_s *bfad, struct bfa_fcs_port_s *port,
+ enum bfa_port_role roles, struct bfad_vf_s *vf_drv,
+ struct bfad_vport_s *vp_drv)
+{
+ bfa_status_t rc;
+ struct bfad_port_s *port_drv;
+
+ if (!vp_drv && !vf_drv) {
+ port_drv = &bfad->pport;
+ port_drv->pvb_type = BFAD_PORT_PHYS_BASE;
+ } else if (!vp_drv && vf_drv) {
+ port_drv = &vf_drv->base_port;
+ port_drv->pvb_type = BFAD_PORT_VF_BASE;
+ } else if (vp_drv && !vf_drv) {
+ port_drv = &vp_drv->drv_port;
+ port_drv->pvb_type = BFAD_PORT_PHYS_VPORT;
+ } else {
+ port_drv = &vp_drv->drv_port;
+ port_drv->pvb_type = BFAD_PORT_VF_VPORT;
+ }
+
+ port_drv->fcs_port = port;
+ port_drv->roles = roles;
+ rc = bfad_fc4_port_new(bfad, port_drv, roles);
+ if (rc != BFA_STATUS_OK) {
+ bfad_fc4_port_delete(bfad, port_drv, roles);
+ port_drv = NULL;
+ }
+
+ return port_drv;
+}
+
+void
+bfa_fcb_port_delete(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv)
+{
+ struct bfad_port_s *port_drv;
+
+ /*
+ * this will be only called from rmmod context
+ */
+ if (vp_drv && !vp_drv->comp_del) {
+ port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv);
+ bfa_trc(bfad, roles);
+ bfad_fc4_port_delete(bfad, port_drv, roles);
+ }
+}
+
+void
+bfa_fcb_port_online(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv)
+{
+ struct bfad_port_s *port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv);
+
+ if (roles & BFA_PORT_ROLE_FCP_IM)
+ bfad_im_port_online(bfad, port_drv);
+
+ if (roles & BFA_PORT_ROLE_FCP_TM)
+ bfad_tm_port_online(bfad, port_drv);
+
+ if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable)
+ bfad_ipfc_port_online(bfad, port_drv);
+
+ bfad->bfad_flags |= BFAD_PORT_ONLINE;
+}
+
+void
+bfa_fcb_port_offline(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv)
+{
+ struct bfad_port_s *port_drv = bfad_get_drv_port(bfad, vf_drv, vp_drv);
+
+ if (roles & BFA_PORT_ROLE_FCP_IM)
+ bfad_im_port_offline(bfad, port_drv);
+
+ if (roles & BFA_PORT_ROLE_FCP_TM)
+ bfad_tm_port_offline(bfad, port_drv);
+
+ if ((roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable)
+ bfad_ipfc_port_offline(bfad, port_drv);
+}
+
+void
+bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv)
+{
+ if (vport_drv->comp_del) {
+ complete(vport_drv->comp_del);
+ return;
+ }
+
+ kfree(vport_drv);
+}
+
+/**
+ * FCS RPORT alloc callback, after successful PLOGI by FCS
+ */
+bfa_status_t
+bfa_fcb_rport_alloc(struct bfad_s *bfad, struct bfa_fcs_rport_s **rport,
+ struct bfad_rport_s **rport_drv)
+{
+ bfa_status_t rc = BFA_STATUS_OK;
+
+ *rport_drv = kzalloc(sizeof(struct bfad_rport_s), GFP_ATOMIC);
+ if (*rport_drv == NULL) {
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+
+ *rport = &(*rport_drv)->fcs_rport;
+
+ext:
+ return rc;
+}
+
+
+
+void
+bfad_hal_mem_release(struct bfad_s *bfad)
+{
+ int i;
+ struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo;
+ struct bfa_mem_elem_s *meminfo_elem;
+
+ for (i = 0; i < BFA_MEM_TYPE_MAX; i++) {
+ meminfo_elem = &hal_meminfo->meminfo[i];
+ if (meminfo_elem->kva != NULL) {
+ switch (meminfo_elem->mem_type) {
+ case BFA_MEM_TYPE_KVA:
+ vfree(meminfo_elem->kva);
+ break;
+ case BFA_MEM_TYPE_DMA:
+ dma_free_coherent(&bfad->pcidev->dev,
+ meminfo_elem->mem_len,
+ meminfo_elem->kva,
+ (dma_addr_t) meminfo_elem->dma);
+ break;
+ default:
+ bfa_assert(0);
+ break;
+ }
+ }
+ }
+
+ memset(hal_meminfo, 0, sizeof(struct bfa_meminfo_s));
+}
+
+void
+bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg)
+{
+ if (num_rports > 0)
+ bfa_cfg->fwcfg.num_rports = num_rports;
+ if (num_ios > 0)
+ bfa_cfg->fwcfg.num_ioim_reqs = num_ios;
+ if (num_tms > 0)
+ bfa_cfg->fwcfg.num_tskim_reqs = num_tms;
+ if (num_fcxps > 0)
+ bfa_cfg->fwcfg.num_fcxp_reqs = num_fcxps;
+ if (num_ufbufs > 0)
+ bfa_cfg->fwcfg.num_uf_bufs = num_ufbufs;
+ if (reqq_size > 0)
+ bfa_cfg->drvcfg.num_reqq_elems = reqq_size;
+ if (rspq_size > 0)
+ bfa_cfg->drvcfg.num_rspq_elems = rspq_size;
+ if (num_sgpgs > 0)
+ bfa_cfg->drvcfg.num_sgpgs = num_sgpgs;
+
+ /*
+ * populate the hal values back to the driver for sysfs use.
+ * otherwise, the default values will be shown as 0 in sysfs
+ */
+ num_rports = bfa_cfg->fwcfg.num_rports;
+ num_ios = bfa_cfg->fwcfg.num_ioim_reqs;
+ num_tms = bfa_cfg->fwcfg.num_tskim_reqs;
+ num_fcxps = bfa_cfg->fwcfg.num_fcxp_reqs;
+ num_ufbufs = bfa_cfg->fwcfg.num_uf_bufs;
+ reqq_size = bfa_cfg->drvcfg.num_reqq_elems;
+ rspq_size = bfa_cfg->drvcfg.num_rspq_elems;
+ num_sgpgs = bfa_cfg->drvcfg.num_sgpgs;
+}
+
+bfa_status_t
+bfad_hal_mem_alloc(struct bfad_s *bfad)
+{
+ struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo;
+ struct bfa_mem_elem_s *meminfo_elem;
+ bfa_status_t rc = BFA_STATUS_OK;
+ dma_addr_t phys_addr;
+ int retry_count = 0;
+ int reset_value = 1;
+ int min_num_sgpgs = 512;
+ void *kva;
+ int i;
+
+ bfa_cfg_get_default(&bfad->ioc_cfg);
+
+retry:
+ bfad_update_hal_cfg(&bfad->ioc_cfg);
+ bfad->cfg_data.ioc_queue_depth = bfad->ioc_cfg.fwcfg.num_ioim_reqs;
+ bfa_cfg_get_meminfo(&bfad->ioc_cfg, hal_meminfo);
+
+ for (i = 0; i < BFA_MEM_TYPE_MAX; i++) {
+ meminfo_elem = &hal_meminfo->meminfo[i];
+ switch (meminfo_elem->mem_type) {
+ case BFA_MEM_TYPE_KVA:
+ kva = vmalloc(meminfo_elem->mem_len);
+ if (kva == NULL) {
+ bfad_hal_mem_release(bfad);
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+ memset(kva, 0, meminfo_elem->mem_len);
+ meminfo_elem->kva = kva;
+ break;
+ case BFA_MEM_TYPE_DMA:
+ kva = dma_alloc_coherent(&bfad->pcidev->dev,
+ meminfo_elem->mem_len,
+ &phys_addr, GFP_KERNEL);
+ if (kva == NULL) {
+ bfad_hal_mem_release(bfad);
+ /*
+ * If we cannot allocate with default
+ * num_sgpages try with half the value.
+ */
+ if (num_sgpgs > min_num_sgpgs) {
+ printk(KERN_INFO "bfad[%d]: memory"
+ " allocation failed with"
+ " num_sgpgs: %d\n",
+ bfad->inst_no, num_sgpgs);
+ nextLowerInt(&num_sgpgs);
+ printk(KERN_INFO "bfad[%d]: trying to"
+ " allocate memory with"
+ " num_sgpgs: %d\n",
+ bfad->inst_no, num_sgpgs);
+ retry_count++;
+ goto retry;
+ } else {
+ if (num_sgpgs_parm > 0)
+ num_sgpgs = num_sgpgs_parm;
+ else {
+ reset_value =
+ (1 << retry_count);
+ num_sgpgs *= reset_value;
+ }
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+ }
+
+ if (num_sgpgs_parm > 0)
+ num_sgpgs = num_sgpgs_parm;
+ else {
+ reset_value = (1 << retry_count);
+ num_sgpgs *= reset_value;
+ }
+
+ memset(kva, 0, meminfo_elem->mem_len);
+ meminfo_elem->kva = kva;
+ meminfo_elem->dma = phys_addr;
+ break;
+ default:
+ break;
+
+ }
+ }
+ext:
+ return rc;
+}
+
+/**
+ * Create a vport under a vf.
+ */
+bfa_status_t
+bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg)
+{
+ struct bfad_vport_s *vport;
+ int rc = BFA_STATUS_OK;
+ unsigned long flags;
+ struct completion fcomp;
+
+ vport = kzalloc(sizeof(struct bfad_vport_s), GFP_KERNEL);
+ if (!vport) {
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+
+ vport->drv_port.bfad = bfad;
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ rc = bfa_fcs_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, vf_id,
+ port_cfg, vport);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (rc != BFA_STATUS_OK)
+ goto ext_free_vport;
+
+ if (port_cfg->roles & BFA_PORT_ROLE_FCP_IM) {
+ rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port);
+ if (rc != BFA_STATUS_OK)
+ goto ext_free_fcs_vport;
+ }
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_fcs_vport_start(&vport->fcs_vport);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ return BFA_STATUS_OK;
+
+ext_free_fcs_vport:
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ vport->comp_del = &fcomp;
+ init_completion(vport->comp_del);
+ bfa_fcs_vport_delete(&vport->fcs_vport);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ wait_for_completion(vport->comp_del);
+ext_free_vport:
+ kfree(vport);
+ext:
+ return rc;
+}
+
+/**
+ * Create a vf and its base vport implicitely.
+ */
+bfa_status_t
+bfad_vf_create(struct bfad_s *bfad, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg)
+{
+ struct bfad_vf_s *vf;
+ int rc = BFA_STATUS_OK;
+
+ vf = kzalloc(sizeof(struct bfad_vf_s), GFP_KERNEL);
+ if (!vf) {
+ rc = BFA_STATUS_FAILED;
+ goto ext;
+ }
+
+ rc = bfa_fcs_vf_create(&vf->fcs_vf, &bfad->bfa_fcs, vf_id, port_cfg,
+ vf);
+ if (rc != BFA_STATUS_OK)
+ kfree(vf);
+ext:
+ return rc;
+}
+
+void
+bfad_bfa_tmo(unsigned long data)
+{
+ struct bfad_s *bfad = (struct bfad_s *)data;
+ unsigned long flags;
+ struct list_head doneq;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ bfa_timer_tick(&bfad->bfa);
+
+ bfa_comp_deq(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (!list_empty(&doneq)) {
+ bfa_comp_process(&bfad->bfa, &doneq);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_comp_free(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ }
+
+ mod_timer(&bfad->hal_tmo, jiffies + msecs_to_jiffies(BFA_TIMER_FREQ));
+}
+
+void
+bfad_init_timer(struct bfad_s *bfad)
+{
+ init_timer(&bfad->hal_tmo);
+ bfad->hal_tmo.function = bfad_bfa_tmo;
+ bfad->hal_tmo.data = (unsigned long)bfad;
+
+ mod_timer(&bfad->hal_tmo, jiffies + msecs_to_jiffies(BFA_TIMER_FREQ));
+}
+
+int
+bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad)
+{
+ unsigned long bar0_len;
+ int rc = -ENODEV;
+
+ if (pci_enable_device(pdev)) {
+ BFA_PRINTF(BFA_ERR, "pci_enable_device fail %p\n", pdev);
+ goto out;
+ }
+
+ if (pci_request_regions(pdev, BFAD_DRIVER_NAME))
+ goto out_disable_device;
+
+ pci_set_master(pdev);
+
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) {
+ BFA_PRINTF(BFA_ERR, "pci_set_dma_mask fail %p\n", pdev);
+ goto out_release_region;
+ }
+
+ bfad->pci_bar0_map = pci_resource_start(pdev, 0);
+ bar0_len = pci_resource_len(pdev, 0);
+ bfad->pci_bar0_kva = ioremap(bfad->pci_bar0_map, bar0_len);
+
+ if (bfad->pci_bar0_kva == NULL) {
+ BFA_PRINTF(BFA_ERR, "Fail to map bar0\n");
+ goto out_release_region;
+ }
+
+ bfad->hal_pcidev.pci_slot = PCI_SLOT(pdev->devfn);
+ bfad->hal_pcidev.pci_func = PCI_FUNC(pdev->devfn);
+ bfad->hal_pcidev.pci_bar_kva = bfad->pci_bar0_kva;
+ bfad->hal_pcidev.device_id = pdev->device;
+ bfad->pci_name = pci_name(pdev);
+
+ bfad->pci_attr.vendor_id = pdev->vendor;
+ bfad->pci_attr.device_id = pdev->device;
+ bfad->pci_attr.ssid = pdev->subsystem_device;
+ bfad->pci_attr.ssvid = pdev->subsystem_vendor;
+ bfad->pci_attr.pcifn = PCI_FUNC(pdev->devfn);
+
+ bfad->pcidev = pdev;
+ return 0;
+
+out_release_region:
+ pci_release_regions(pdev);
+out_disable_device:
+ pci_disable_device(pdev);
+out:
+ return rc;
+}
+
+void
+bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad)
+{
+#if defined(__ia64__)
+ pci_iounmap(pdev, bfad->pci_bar0_kva);
+#else
+ iounmap(bfad->pci_bar0_kva);
+#endif
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+}
+
+void
+bfad_fcs_port_cfg(struct bfad_s *bfad)
+{
+ struct bfa_port_cfg_s port_cfg;
+ struct bfa_pport_attr_s attr;
+ char symname[BFA_SYMNAME_MAXLEN];
+
+ sprintf(symname, "%s-%d", BFAD_DRIVER_NAME, bfad->inst_no);
+ memcpy(port_cfg.sym_name.symname, symname, strlen(symname));
+ bfa_pport_get_attr(&bfad->bfa, &attr);
+ port_cfg.nwwn = attr.nwwn;
+ port_cfg.pwwn = attr.pwwn;
+
+ bfa_fcs_cfg_base_port(&bfad->bfa_fcs, &port_cfg);
+}
+
+bfa_status_t
+bfad_drv_init(struct bfad_s *bfad)
+{
+ bfa_status_t rc;
+ unsigned long flags;
+ struct bfa_fcs_driver_info_s driver_info;
+ int i;
+
+ bfad->cfg_data.rport_del_timeout = rport_del_timeout;
+ bfad->cfg_data.lun_queue_depth = bfa_lun_queue_depth;
+ bfad->cfg_data.io_max_sge = bfa_io_max_sge;
+ bfad->cfg_data.binding_method = FCP_PWWN_BINDING;
+
+ rc = bfad_hal_mem_alloc(bfad);
+ if (rc != BFA_STATUS_OK) {
+ printk(KERN_WARNING "bfad%d bfad_hal_mem_alloc failure\n",
+ bfad->inst_no);
+ printk(KERN_WARNING
+ "Not enough memory to attach all Brocade HBA ports,"
+ " System may need more memory.\n");
+ goto out_hal_mem_alloc_failure;
+ }
+
+ bfa_init_log(&bfad->bfa, bfad->logmod);
+ bfa_init_trc(&bfad->bfa, bfad->trcmod);
+ bfa_init_aen(&bfad->bfa, bfad->aen);
+ INIT_LIST_HEAD(&bfad->file_q);
+ INIT_LIST_HEAD(&bfad->file_free_q);
+ for (i = 0; i < BFAD_AEN_MAX_APPS; i++) {
+ bfa_q_qe_init(&bfad->file_buf[i].qe);
+ list_add_tail(&bfad->file_buf[i].qe, &bfad->file_free_q);
+ }
+ bfa_init_plog(&bfad->bfa, &bfad->plog_buf);
+ bfa_plog_init(&bfad->plog_buf);
+ bfa_plog_str(&bfad->plog_buf, BFA_PL_MID_DRVR, BFA_PL_EID_DRIVER_START,
+ 0, "Driver Attach");
+
+ bfa_attach(&bfad->bfa, bfad, &bfad->ioc_cfg, &bfad->meminfo,
+ &bfad->hal_pcidev);
+
+ init_completion(&bfad->comp);
+
+ /*
+ * Enable Interrupt and wait bfa_init completion
+ */
+ if (bfad_setup_intr(bfad)) {
+ printk(KERN_WARNING "bfad%d: bfad_setup_intr failed\n",
+ bfad->inst_no);
+ goto out_setup_intr_failure;
+ }
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_init(&bfad->bfa);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ /*
+ * Set up interrupt handler for each vectors
+ */
+ if ((bfad->bfad_flags & BFAD_MSIX_ON)
+ && bfad_install_msix_handler(bfad)) {
+ printk(KERN_WARNING "%s: install_msix failed, bfad%d\n",
+ __func__, bfad->inst_no);
+ }
+
+ bfad_init_timer(bfad);
+
+ wait_for_completion(&bfad->comp);
+
+ memset(&driver_info, 0, sizeof(driver_info));
+ strncpy(driver_info.version, BFAD_DRIVER_VERSION,
+ sizeof(driver_info.version) - 1);
+ if (host_name)
+ strncpy(driver_info.host_machine_name, host_name,
+ sizeof(driver_info.host_machine_name) - 1);
+ if (os_name)
+ strncpy(driver_info.host_os_name, os_name,
+ sizeof(driver_info.host_os_name) - 1);
+ if (os_patch)
+ strncpy(driver_info.host_os_patch, os_patch,
+ sizeof(driver_info.host_os_patch) - 1);
+
+ strncpy(driver_info.os_device_name, bfad->pci_name,
+ sizeof(driver_info.os_device_name - 1));
+
+ /*
+ * FCS INIT
+ */
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_fcs_log_init(&bfad->bfa_fcs, bfad->logmod);
+ bfa_fcs_trc_init(&bfad->bfa_fcs, bfad->trcmod);
+ bfa_fcs_aen_init(&bfad->bfa_fcs, bfad->aen);
+ bfa_fcs_init(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE);
+ bfa_fcs_driver_info_init(&bfad->bfa_fcs, &driver_info);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ bfad->bfad_flags |= BFAD_DRV_INIT_DONE;
+ return BFA_STATUS_OK;
+
+out_setup_intr_failure:
+ bfa_detach(&bfad->bfa);
+ bfad_hal_mem_release(bfad);
+out_hal_mem_alloc_failure:
+ return BFA_STATUS_FAILED;
+}
+
+void
+bfad_drv_uninit(struct bfad_s *bfad)
+{
+ del_timer_sync(&bfad->hal_tmo);
+ bfa_isr_disable(&bfad->bfa);
+ bfa_detach(&bfad->bfa);
+ bfad_remove_intr(bfad);
+ bfa_assert(list_empty(&bfad->file_q));
+ bfad_hal_mem_release(bfad);
+}
+
+void
+bfad_drv_start(struct bfad_s *bfad)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_start(&bfad->bfa);
+ bfa_fcs_start(&bfad->bfa_fcs);
+ bfad->bfad_flags |= BFAD_HAL_START_DONE;
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ bfad_fc4_probe_post(bfad);
+}
+
+void
+bfad_drv_stop(struct bfad_s *bfad)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ init_completion(&bfad->comp);
+ bfad->pport.flags |= BFAD_PORT_DELETE;
+ bfa_fcs_exit(&bfad->bfa_fcs);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ wait_for_completion(&bfad->comp);
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ init_completion(&bfad->comp);
+ bfa_stop(&bfad->bfa);
+ bfad->bfad_flags &= ~BFAD_HAL_START_DONE;
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ wait_for_completion(&bfad->comp);
+}
+
+bfa_status_t
+bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role)
+{
+ int rc = BFA_STATUS_OK;
+
+ /*
+ * Allocate scsi_host for the physical port
+ */
+ if ((bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM)
+ && (role & BFA_PORT_ROLE_FCP_IM)) {
+ if (bfad->pport.im_port == NULL) {
+ rc = BFA_STATUS_FAILED;
+ goto out;
+ }
+
+ rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port);
+ if (rc != BFA_STATUS_OK)
+ goto out;
+
+ bfad->pport.roles |= BFA_PORT_ROLE_FCP_IM;
+ }
+
+ bfad->bfad_flags |= BFAD_CFG_PPORT_DONE;
+
+out:
+ return rc;
+}
+
+void
+bfad_uncfg_pport(struct bfad_s *bfad)
+{
+ if ((bfad->pport.roles & BFA_PORT_ROLE_FCP_IPFC) && ipfc_enable) {
+ bfad_ipfc_port_delete(bfad, &bfad->pport);
+ bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IPFC;
+ }
+
+ if ((bfad_supported_fc4s & BFA_PORT_ROLE_FCP_IM)
+ && (bfad->pport.roles & BFA_PORT_ROLE_FCP_IM)) {
+ bfad_im_scsi_host_free(bfad, bfad->pport.im_port);
+ bfad_im_port_clean(bfad->pport.im_port);
+ kfree(bfad->pport.im_port);
+ bfad->pport.roles &= ~BFA_PORT_ROLE_FCP_IM;
+ }
+
+ bfad->bfad_flags &= ~BFAD_CFG_PPORT_DONE;
+}
+
+void
+bfad_drv_log_level_set(struct bfad_s *bfad)
+{
+ if (log_level > BFA_LOG_INVALID && log_level <= BFA_LOG_LEVEL_MAX)
+ bfa_log_set_level_all(&bfad->log_data, log_level);
+}
+
+ /*
+ * PCI_entry PCI driver entries * {
+ */
+
+/**
+ * PCI probe entry.
+ */
+int
+bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid)
+{
+ struct bfad_s *bfad;
+ int error = -ENODEV, retval;
+ char buf[16];
+
+ /*
+ * For single port cards - only claim function 0
+ */
+ if ((pdev->device == BFA_PCI_DEVICE_ID_FC_8G1P)
+ && (PCI_FUNC(pdev->devfn) != 0))
+ return -ENODEV;
+
+ BFA_TRACE(BFA_INFO, "bfad_pci_probe entry");
+
+ bfad = kzalloc(sizeof(struct bfad_s), GFP_KERNEL);
+ if (!bfad) {
+ error = -ENOMEM;
+ goto out;
+ }
+
+ bfad->trcmod = kzalloc(sizeof(struct bfa_trc_mod_s), GFP_KERNEL);
+ if (!bfad->trcmod) {
+ printk(KERN_WARNING "Error alloc trace buffer!\n");
+ error = -ENOMEM;
+ goto out_alloc_trace_failure;
+ }
+
+ /*
+ * LOG/TRACE INIT
+ */
+ bfa_trc_init(bfad->trcmod);
+ bfa_trc(bfad, bfad_inst);
+
+ bfad->logmod = &bfad->log_data;
+ sprintf(buf, "%d", bfad_inst);
+ bfa_log_init(bfad->logmod, buf, bfa_os_printf);
+
+ bfad_drv_log_level_set(bfad);
+
+ bfad->aen = &bfad->aen_buf;
+
+ if (!(bfad_load_fwimg(pdev))) {
+ printk(KERN_WARNING "bfad_load_fwimg failure!\n");
+ kfree(bfad->trcmod);
+ goto out_alloc_trace_failure;
+ }
+
+ retval = bfad_pci_init(pdev, bfad);
+ if (retval) {
+ printk(KERN_WARNING "bfad_pci_init failure!\n");
+ error = retval;
+ goto out_pci_init_failure;
+ }
+
+ mutex_lock(&bfad_mutex);
+ bfad->inst_no = bfad_inst++;
+ list_add_tail(&bfad->list_entry, &bfad_list);
+ mutex_unlock(&bfad_mutex);
+
+ spin_lock_init(&bfad->bfad_lock);
+ pci_set_drvdata(pdev, bfad);
+
+ bfad->ref_count = 0;
+ bfad->pport.bfad = bfad;
+
+ retval = bfad_drv_init(bfad);
+ if (retval != BFA_STATUS_OK)
+ goto out_drv_init_failure;
+ if (!(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) {
+ printk(KERN_WARNING "bfad%d: hal init failed\n", bfad->inst_no);
+ goto ok;
+ }
+
+ /*
+ * PPORT FCS config
+ */
+ bfad_fcs_port_cfg(bfad);
+
+ retval = bfad_cfg_pport(bfad, BFA_PORT_ROLE_FCP_IM);
+ if (retval != BFA_STATUS_OK)
+ goto out_cfg_pport_failure;
+
+ /*
+ * BFAD level FC4 (IM/TM/IPFC) specific resource allocation
+ */
+ retval = bfad_fc4_probe(bfad);
+ if (retval != BFA_STATUS_OK) {
+ printk(KERN_WARNING "bfad_fc4_probe failed\n");
+ goto out_fc4_probe_failure;
+ }
+
+ bfad_drv_start(bfad);
+
+ /*
+ * If bfa_linkup_delay is set to -1 default; try to retrive the
+ * value using the bfad_os_get_linkup_delay(); else use the
+ * passed in module param value as the bfa_linkup_delay.
+ */
+ if (bfa_linkup_delay < 0) {
+ bfa_linkup_delay = bfad_os_get_linkup_delay(bfad);
+ bfad_os_rport_online_wait(bfad);
+ bfa_linkup_delay = -1;
+ } else {
+ bfad_os_rport_online_wait(bfad);
+ }
+
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_DEVICE_CLAIMED, bfad->pci_name);
+ok:
+ return 0;
+
+out_fc4_probe_failure:
+ bfad_fc4_probe_undo(bfad);
+ bfad_uncfg_pport(bfad);
+out_cfg_pport_failure:
+ bfad_drv_uninit(bfad);
+out_drv_init_failure:
+ mutex_lock(&bfad_mutex);
+ bfad_inst--;
+ list_del(&bfad->list_entry);
+ mutex_unlock(&bfad_mutex);
+ bfad_pci_uninit(pdev, bfad);
+out_pci_init_failure:
+ kfree(bfad->trcmod);
+out_alloc_trace_failure:
+ kfree(bfad);
+out:
+ return error;
+}
+
+/**
+ * PCI remove entry.
+ */
+void
+bfad_pci_remove(struct pci_dev *pdev)
+{
+ struct bfad_s *bfad = pci_get_drvdata(pdev);
+ unsigned long flags;
+
+ bfa_trc(bfad, bfad->inst_no);
+
+ if ((bfad->bfad_flags & BFAD_DRV_INIT_DONE)
+ && !(bfad->bfad_flags & BFAD_HAL_INIT_DONE)) {
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ init_completion(&bfad->comp);
+ bfa_stop(&bfad->bfa);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ wait_for_completion(&bfad->comp);
+
+ bfad_remove_intr(bfad);
+ del_timer_sync(&bfad->hal_tmo);
+ goto hal_detach;
+ } else if (!(bfad->bfad_flags & BFAD_DRV_INIT_DONE)) {
+ goto remove_sysfs;
+ }
+
+ if (bfad->bfad_flags & BFAD_HAL_START_DONE)
+ bfad_drv_stop(bfad);
+
+ bfad_remove_intr(bfad);
+
+ del_timer_sync(&bfad->hal_tmo);
+ bfad_fc4_probe_undo(bfad);
+
+ if (bfad->bfad_flags & BFAD_CFG_PPORT_DONE)
+ bfad_uncfg_pport(bfad);
+
+hal_detach:
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_detach(&bfad->bfa);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ bfad_hal_mem_release(bfad);
+remove_sysfs:
+
+ mutex_lock(&bfad_mutex);
+ bfad_inst--;
+ list_del(&bfad->list_entry);
+ mutex_unlock(&bfad_mutex);
+ bfad_pci_uninit(pdev, bfad);
+
+ kfree(bfad->trcmod);
+ kfree(bfad);
+}
+
+
+static struct pci_device_id bfad_id_table[] = {
+ {
+ .vendor = BFA_PCI_VENDOR_ID_BROCADE,
+ .device = BFA_PCI_DEVICE_ID_FC_8G2P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .vendor = BFA_PCI_VENDOR_ID_BROCADE,
+ .device = BFA_PCI_DEVICE_ID_FC_8G1P,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .vendor = BFA_PCI_VENDOR_ID_BROCADE,
+ .device = BFA_PCI_DEVICE_ID_CT,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = (PCI_CLASS_SERIAL_FIBER << 8),
+ .class_mask = ~0,
+ },
+
+ {0, 0},
+};
+
+MODULE_DEVICE_TABLE(pci, bfad_id_table);
+
+static struct pci_driver bfad_pci_driver = {
+ .name = BFAD_DRIVER_NAME,
+ .id_table = bfad_id_table,
+ .probe = bfad_pci_probe,
+ .remove = __devexit_p(bfad_pci_remove),
+};
+
+/**
+ * Linux driver module functions
+ */
+bfa_status_t
+bfad_fc4_module_init(void)
+{
+ int rc;
+
+ rc = bfad_im_module_init();
+ if (rc != BFA_STATUS_OK)
+ goto ext;
+
+ bfad_tm_module_init();
+ if (ipfc_enable)
+ bfad_ipfc_module_init();
+ext:
+ return rc;
+}
+
+void
+bfad_fc4_module_exit(void)
+{
+ if (ipfc_enable)
+ bfad_ipfc_module_exit();
+ bfad_tm_module_exit();
+ bfad_im_module_exit();
+}
+
+/**
+ * Driver module init.
+ */
+static int __init
+bfad_init(void)
+{
+ int error = 0;
+
+ printk(KERN_INFO "Brocade BFA FC/FCOE SCSI driver - version: %s\n",
+ BFAD_DRIVER_VERSION);
+
+ if (num_sgpgs > 0)
+ num_sgpgs_parm = num_sgpgs;
+
+ error = bfad_fc4_module_init();
+ if (error) {
+ error = -ENOMEM;
+ printk(KERN_WARNING "bfad_fc4_module_init failure\n");
+ goto ext;
+ }
+
+ if (!strcmp(FCPI_NAME, " fcpim"))
+ bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_IM;
+ if (!strcmp(FCPT_NAME, " fcptm"))
+ bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_TM;
+ if (!strcmp(IPFC_NAME, " ipfc"))
+ bfad_supported_fc4s |= BFA_PORT_ROLE_FCP_IPFC;
+
+ bfa_ioc_auto_recover(ioc_auto_recover);
+ bfa_fcs_rport_set_del_timeout(rport_del_timeout);
+ error = pci_register_driver(&bfad_pci_driver);
+
+ if (error) {
+ printk(KERN_WARNING "bfad pci_register_driver failure\n");
+ goto ext;
+ }
+
+ return 0;
+
+ext:
+ bfad_fc4_module_exit();
+ return error;
+}
+
+/**
+ * Driver module exit.
+ */
+static void __exit
+bfad_exit(void)
+{
+ pci_unregister_driver(&bfad_pci_driver);
+ bfad_fc4_module_exit();
+ bfad_free_fwimg();
+}
+
+#define BFAD_PROTO_NAME FCPI_NAME FCPT_NAME IPFC_NAME
+
+module_init(bfad_init);
+module_exit(bfad_exit);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Brocade Fibre Channel HBA Driver" BFAD_PROTO_NAME);
+MODULE_AUTHOR("Brocade Communications Systems, Inc.");
+MODULE_VERSION(BFAD_DRIVER_VERSION);
+
+
diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c
new file mode 100644
index 000000000000..9129ae3040ff
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_attr.c
@@ -0,0 +1,649 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_attr.c Linux driver configuration interface module.
+ */
+
+#include "bfad_drv.h"
+#include "bfad_im.h"
+#include "bfad_trcmod.h"
+#include "bfad_attr.h"
+
+/**
+ * FC_transport_template FC transport template
+ */
+
+/**
+ * FC transport template entry, get SCSI target port ID.
+ */
+void
+bfad_im_get_starget_port_id(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost;
+ struct bfad_im_port_s *im_port;
+ struct bfad_s *bfad;
+ struct bfad_itnim_s *itnim = NULL;
+ u32 fc_id = -1;
+ unsigned long flags;
+
+ shost = bfad_os_starget_to_shost(starget);
+ im_port = (struct bfad_im_port_s *) shost->hostdata[0];
+ bfad = im_port->bfad;
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ itnim = bfad_os_get_itnim(im_port, starget->id);
+ if (itnim)
+ fc_id = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim);
+
+ fc_starget_port_id(starget) = fc_id;
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+/**
+ * FC transport template entry, get SCSI target nwwn.
+ */
+void
+bfad_im_get_starget_node_name(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost;
+ struct bfad_im_port_s *im_port;
+ struct bfad_s *bfad;
+ struct bfad_itnim_s *itnim = NULL;
+ u64 node_name = 0;
+ unsigned long flags;
+
+ shost = bfad_os_starget_to_shost(starget);
+ im_port = (struct bfad_im_port_s *) shost->hostdata[0];
+ bfad = im_port->bfad;
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ itnim = bfad_os_get_itnim(im_port, starget->id);
+ if (itnim)
+ node_name = bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim);
+
+ fc_starget_node_name(starget) = bfa_os_htonll(node_name);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+/**
+ * FC transport template entry, get SCSI target pwwn.
+ */
+void
+bfad_im_get_starget_port_name(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost;
+ struct bfad_im_port_s *im_port;
+ struct bfad_s *bfad;
+ struct bfad_itnim_s *itnim = NULL;
+ u64 port_name = 0;
+ unsigned long flags;
+
+ shost = bfad_os_starget_to_shost(starget);
+ im_port = (struct bfad_im_port_s *) shost->hostdata[0];
+ bfad = im_port->bfad;
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ itnim = bfad_os_get_itnim(im_port, starget->id);
+ if (itnim)
+ port_name = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim);
+
+ fc_starget_port_name(starget) = bfa_os_htonll(port_name);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+/**
+ * FC transport template entry, get SCSI host port ID.
+ */
+void
+bfad_im_get_host_port_id(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_port_s *port = im_port->port;
+
+ fc_host_port_id(shost) =
+ bfa_os_hton3b(bfa_fcs_port_get_fcid(port->fcs_port));
+}
+
+
+
+
+
+struct Scsi_Host *
+bfad_os_starget_to_shost(struct scsi_target *starget)
+{
+ return dev_to_shost(starget->dev.parent);
+}
+
+/**
+ * FC transport template entry, get SCSI host port type.
+ */
+static void
+bfad_im_get_host_port_type(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_pport_attr_s attr;
+
+ bfa_pport_get_attr(&bfad->bfa, &attr);
+
+ switch (attr.port_type) {
+ case BFA_PPORT_TYPE_NPORT:
+ fc_host_port_type(shost) = FC_PORTTYPE_NPORT;
+ break;
+ case BFA_PPORT_TYPE_NLPORT:
+ fc_host_port_type(shost) = FC_PORTTYPE_NLPORT;
+ break;
+ case BFA_PPORT_TYPE_P2P:
+ fc_host_port_type(shost) = FC_PORTTYPE_PTP;
+ break;
+ case BFA_PPORT_TYPE_LPORT:
+ fc_host_port_type(shost) = FC_PORTTYPE_LPORT;
+ break;
+ default:
+ fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
+ break;
+ }
+}
+
+/**
+ * FC transport template entry, get SCSI host port state.
+ */
+static void
+bfad_im_get_host_port_state(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_pport_attr_s attr;
+
+ bfa_pport_get_attr(&bfad->bfa, &attr);
+
+ switch (attr.port_state) {
+ case BFA_PPORT_ST_LINKDOWN:
+ fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
+ break;
+ case BFA_PPORT_ST_LINKUP:
+ fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
+ break;
+ case BFA_PPORT_ST_UNINIT:
+ case BFA_PPORT_ST_ENABLING_QWAIT:
+ case BFA_PPORT_ST_ENABLING:
+ case BFA_PPORT_ST_DISABLING_QWAIT:
+ case BFA_PPORT_ST_DISABLING:
+ case BFA_PPORT_ST_DISABLED:
+ case BFA_PPORT_ST_STOPPED:
+ case BFA_PPORT_ST_IOCDOWN:
+ default:
+ fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
+ break;
+ }
+}
+
+/**
+ * FC transport template entry, get SCSI host active fc4s.
+ */
+static void
+bfad_im_get_host_active_fc4s(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_port_s *port = im_port->port;
+
+ memset(fc_host_active_fc4s(shost), 0,
+ sizeof(fc_host_active_fc4s(shost)));
+
+ if (port->supported_fc4s &
+ (BFA_PORT_ROLE_FCP_IM | BFA_PORT_ROLE_FCP_TM))
+ fc_host_active_fc4s(shost)[2] = 1;
+
+ if (port->supported_fc4s & BFA_PORT_ROLE_FCP_IPFC)
+ fc_host_active_fc4s(shost)[3] = 0x20;
+
+ fc_host_active_fc4s(shost)[7] = 1;
+}
+
+/**
+ * FC transport template entry, get SCSI host link speed.
+ */
+static void
+bfad_im_get_host_speed(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_pport_attr_s attr;
+
+ bfa_pport_get_attr(&bfad->bfa, &attr);
+ switch (attr.speed) {
+ case BFA_PPORT_SPEED_8GBPS:
+ fc_host_speed(shost) = FC_PORTSPEED_8GBIT;
+ break;
+ case BFA_PPORT_SPEED_4GBPS:
+ fc_host_speed(shost) = FC_PORTSPEED_4GBIT;
+ break;
+ case BFA_PPORT_SPEED_2GBPS:
+ fc_host_speed(shost) = FC_PORTSPEED_2GBIT;
+ break;
+ case BFA_PPORT_SPEED_1GBPS:
+ fc_host_speed(shost) = FC_PORTSPEED_1GBIT;
+ break;
+ default:
+ fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
+ break;
+ }
+}
+
+/**
+ * FC transport template entry, get SCSI host port type.
+ */
+static void
+bfad_im_get_host_fabric_name(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_port_s *port = im_port->port;
+ wwn_t fabric_nwwn = 0;
+
+ fabric_nwwn = bfa_fcs_port_get_fabric_name(port->fcs_port);
+
+ fc_host_fabric_name(shost) = bfa_os_htonll(fabric_nwwn);
+
+}
+
+/**
+ * FC transport template entry, get BFAD statistics.
+ */
+static struct fc_host_statistics *
+bfad_im_get_stats(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfad_hal_comp fcomp;
+ struct fc_host_statistics *hstats;
+ bfa_status_t rc;
+ unsigned long flags;
+
+ hstats = &bfad->link_stats;
+ init_completion(&fcomp.comp);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ memset(hstats, 0, sizeof(struct fc_host_statistics));
+ rc = bfa_pport_get_stats(&bfad->bfa,
+ (union bfa_pport_stats_u *) hstats,
+ bfad_hcb_comp, &fcomp);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ if (rc != BFA_STATUS_OK)
+ return NULL;
+
+ wait_for_completion(&fcomp.comp);
+
+ return hstats;
+}
+
+/**
+ * FC transport template entry, reset BFAD statistics.
+ */
+static void
+bfad_im_reset_stats(struct Scsi_Host *shost)
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfad_hal_comp fcomp;
+ unsigned long flags;
+ bfa_status_t rc;
+
+ init_completion(&fcomp.comp);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ rc = bfa_pport_clear_stats(&bfad->bfa, bfad_hcb_comp, &fcomp);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (rc != BFA_STATUS_OK)
+ return;
+
+ wait_for_completion(&fcomp.comp);
+
+ return;
+}
+
+/**
+ * FC transport template entry, get rport loss timeout.
+ */
+static void
+bfad_im_get_rport_loss_tmo(struct fc_rport *rport)
+{
+ struct bfad_itnim_data_s *itnim_data = rport->dd_data;
+ struct bfad_itnim_s *itnim = itnim_data->itnim;
+ struct bfad_s *bfad = itnim->im->bfad;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ rport->dev_loss_tmo = bfa_fcpim_path_tov_get(&bfad->bfa);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+/**
+ * FC transport template entry, set rport loss timeout.
+ */
+static void
+bfad_im_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout)
+{
+ struct bfad_itnim_data_s *itnim_data = rport->dd_data;
+ struct bfad_itnim_s *itnim = itnim_data->itnim;
+ struct bfad_s *bfad = itnim->im->bfad;
+ unsigned long flags;
+
+ if (timeout > 0) {
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_fcpim_path_tov_set(&bfad->bfa, timeout);
+ rport->dev_loss_tmo = bfa_fcpim_path_tov_get(&bfad->bfa);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ }
+
+}
+
+struct fc_function_template bfad_im_fc_function_template = {
+
+ /* Target dynamic attributes */
+ .get_starget_port_id = bfad_im_get_starget_port_id,
+ .show_starget_port_id = 1,
+ .get_starget_node_name = bfad_im_get_starget_node_name,
+ .show_starget_node_name = 1,
+ .get_starget_port_name = bfad_im_get_starget_port_name,
+ .show_starget_port_name = 1,
+
+ /* Host dynamic attribute */
+ .get_host_port_id = bfad_im_get_host_port_id,
+ .show_host_port_id = 1,
+
+ /* Host fixed attributes */
+ .show_host_node_name = 1,
+ .show_host_port_name = 1,
+ .show_host_supported_classes = 1,
+ .show_host_supported_fc4s = 1,
+ .show_host_supported_speeds = 1,
+ .show_host_maxframe_size = 1,
+
+ /* More host dynamic attributes */
+ .show_host_port_type = 1,
+ .get_host_port_type = bfad_im_get_host_port_type,
+ .show_host_port_state = 1,
+ .get_host_port_state = bfad_im_get_host_port_state,
+ .show_host_active_fc4s = 1,
+ .get_host_active_fc4s = bfad_im_get_host_active_fc4s,
+ .show_host_speed = 1,
+ .get_host_speed = bfad_im_get_host_speed,
+ .show_host_fabric_name = 1,
+ .get_host_fabric_name = bfad_im_get_host_fabric_name,
+
+ .show_host_symbolic_name = 1,
+
+ /* Statistics */
+ .get_fc_host_stats = bfad_im_get_stats,
+ .reset_fc_host_stats = bfad_im_reset_stats,
+
+ /* Allocation length for host specific data */
+ .dd_fcrport_size = sizeof(struct bfad_itnim_data_s *),
+
+ /* Remote port fixed attributes */
+ .show_rport_maxframe_size = 1,
+ .show_rport_supported_classes = 1,
+ .show_rport_dev_loss_tmo = 1,
+ .get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo,
+ .set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo,
+};
+
+/**
+ * Scsi_Host_attrs SCSI host attributes
+ */
+static ssize_t
+bfad_im_serial_num_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ioc_attr.adapter_attr.serial_num);
+}
+
+static ssize_t
+bfad_im_model_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.model);
+}
+
+static ssize_t
+bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ioc_attr.adapter_attr.model_descr);
+}
+
+static ssize_t
+bfad_im_node_name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_port_s *port = im_port->port;
+ u64 nwwn;
+
+ nwwn = bfa_fcs_port_get_nwwn(port->fcs_port);
+ return snprintf(buf, PAGE_SIZE, "0x%llx\n", bfa_os_htonll(nwwn));
+}
+
+static ssize_t
+bfad_im_symbolic_name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+
+ return snprintf(buf, PAGE_SIZE, "Brocade %s FV%s DV%s\n",
+ ioc_attr.adapter_attr.model,
+ ioc_attr.adapter_attr.fw_ver, BFAD_DRIVER_VERSION);
+}
+
+static ssize_t
+bfad_im_hw_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.hw_ver);
+}
+
+static ssize_t
+bfad_im_drv_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", BFAD_DRIVER_VERSION);
+}
+
+static ssize_t
+bfad_im_optionrom_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n",
+ ioc_attr.adapter_attr.optrom_ver);
+}
+
+static ssize_t
+bfad_im_fw_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%s\n", ioc_attr.adapter_attr.fw_ver);
+}
+
+static ssize_t
+bfad_im_num_of_ports_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioc_attr_s ioc_attr;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+ return snprintf(buf, PAGE_SIZE, "%d\n", ioc_attr.adapter_attr.nports);
+}
+
+static ssize_t
+bfad_im_drv_name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", BFAD_DRIVER_NAME);
+}
+
+static ssize_t
+bfad_im_num_of_discovered_ports_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct Scsi_Host *shost = class_to_shost(dev);
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_port_s *port = im_port->port;
+ struct bfad_s *bfad = im_port->bfad;
+ int nrports = 2048;
+ wwn_t *rports = NULL;
+ unsigned long flags;
+
+ rports = kzalloc(sizeof(wwn_t) * nrports , GFP_ATOMIC);
+ if (rports == NULL)
+ return -ENOMEM;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_fcs_port_get_rports(port->fcs_port, rports, &nrports);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ kfree(rports);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", nrports);
+}
+
+static DEVICE_ATTR(serial_number, S_IRUGO,
+ bfad_im_serial_num_show, NULL);
+static DEVICE_ATTR(model, S_IRUGO, bfad_im_model_show, NULL);
+static DEVICE_ATTR(model_description, S_IRUGO,
+ bfad_im_model_desc_show, NULL);
+static DEVICE_ATTR(node_name, S_IRUGO, bfad_im_node_name_show, NULL);
+static DEVICE_ATTR(symbolic_name, S_IRUGO,
+ bfad_im_symbolic_name_show, NULL);
+static DEVICE_ATTR(hardware_version, S_IRUGO,
+ bfad_im_hw_version_show, NULL);
+static DEVICE_ATTR(driver_version, S_IRUGO,
+ bfad_im_drv_version_show, NULL);
+static DEVICE_ATTR(option_rom_version, S_IRUGO,
+ bfad_im_optionrom_version_show, NULL);
+static DEVICE_ATTR(firmware_version, S_IRUGO,
+ bfad_im_fw_version_show, NULL);
+static DEVICE_ATTR(number_of_ports, S_IRUGO,
+ bfad_im_num_of_ports_show, NULL);
+static DEVICE_ATTR(driver_name, S_IRUGO, bfad_im_drv_name_show, NULL);
+static DEVICE_ATTR(number_of_discovered_ports, S_IRUGO,
+ bfad_im_num_of_discovered_ports_show, NULL);
+
+struct device_attribute *bfad_im_host_attrs[] = {
+ &dev_attr_serial_number,
+ &dev_attr_model,
+ &dev_attr_model_description,
+ &dev_attr_node_name,
+ &dev_attr_symbolic_name,
+ &dev_attr_hardware_version,
+ &dev_attr_driver_version,
+ &dev_attr_option_rom_version,
+ &dev_attr_firmware_version,
+ &dev_attr_number_of_ports,
+ &dev_attr_driver_name,
+ &dev_attr_number_of_discovered_ports,
+ NULL,
+};
+
+struct device_attribute *bfad_im_vport_attrs[] = {
+ &dev_attr_serial_number,
+ &dev_attr_model,
+ &dev_attr_model_description,
+ &dev_attr_node_name,
+ &dev_attr_symbolic_name,
+ &dev_attr_hardware_version,
+ &dev_attr_driver_version,
+ &dev_attr_option_rom_version,
+ &dev_attr_firmware_version,
+ &dev_attr_number_of_ports,
+ &dev_attr_driver_name,
+ &dev_attr_number_of_discovered_ports,
+ NULL,
+};
+
+
diff --git a/drivers/scsi/bfa/bfad_attr.h b/drivers/scsi/bfa/bfad_attr.h
new file mode 100644
index 000000000000..4d3312da6a81
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_attr.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFAD_ATTR_H__
+#define __BFAD_ATTR_H__
+/**
+ * bfad_attr.h VMware driver configuration interface module.
+ */
+
+/**
+ * FC_transport_template FC transport template
+ */
+
+struct Scsi_Host*
+bfad_os_dev_to_shost(struct scsi_target *starget);
+
+/**
+ * FC transport template entry, get SCSI target port ID.
+ */
+void
+bfad_im_get_starget_port_id(struct scsi_target *starget);
+
+/**
+ * FC transport template entry, get SCSI target nwwn.
+ */
+void
+bfad_im_get_starget_node_name(struct scsi_target *starget);
+
+/**
+ * FC transport template entry, get SCSI target pwwn.
+ */
+void
+bfad_im_get_starget_port_name(struct scsi_target *starget);
+
+/**
+ * FC transport template entry, get SCSI host port ID.
+ */
+void
+bfad_im_get_host_port_id(struct Scsi_Host *shost);
+
+/**
+ * FC transport template entry, issue a LIP.
+ */
+int
+bfad_im_issue_fc_host_lip(struct Scsi_Host *shost);
+
+struct Scsi_Host*
+bfad_os_starget_to_shost(struct scsi_target *starget);
+
+
+#endif /* __BFAD_ATTR_H__ */
diff --git a/drivers/scsi/bfa/bfad_drv.h b/drivers/scsi/bfa/bfad_drv.h
new file mode 100644
index 000000000000..172c81e25c1c
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_drv.h
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * Contains base driver definitions.
+ */
+
+/**
+ * bfa_drv.h Linux driver data structures.
+ */
+
+#ifndef __BFAD_DRV_H__
+#define __BFAD_DRV_H__
+
+#include "bfa_os_inc.h"
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <fcs/bfa_fcs.h>
+#include <defs/bfa_defs_pci.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_rport.h>
+#include <fcs/bfa_fcs_rport.h>
+#include <defs/bfa_defs_vport.h>
+#include <fcs/bfa_fcs_vport.h>
+
+#include <cs/bfa_plog.h>
+#include "aen/bfa_aen.h"
+#include <log/bfa_log_linux.h>
+
+#define BFAD_DRIVER_NAME "bfa"
+#ifdef BFA_DRIVER_VERSION
+#define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION
+#else
+#define BFAD_DRIVER_VERSION "2.0.0.0"
+#endif
+
+
+#define BFAD_IRQ_FLAGS IRQF_SHARED
+
+/*
+ * BFAD flags
+ */
+#define BFAD_MSIX_ON 0x00000001
+#define BFAD_HAL_INIT_DONE 0x00000002
+#define BFAD_DRV_INIT_DONE 0x00000004
+#define BFAD_CFG_PPORT_DONE 0x00000008
+#define BFAD_HAL_START_DONE 0x00000010
+#define BFAD_PORT_ONLINE 0x00000020
+#define BFAD_RPORT_ONLINE 0x00000040
+
+#define BFAD_PORT_DELETE 0x00000001
+
+/*
+ * BFAD related definition
+ */
+#define SCSI_SCAN_DELAY HZ
+#define BFAD_STOP_TIMEOUT 30
+#define BFAD_SUSPEND_TIMEOUT BFAD_STOP_TIMEOUT
+
+/*
+ * BFAD configuration parameter default values
+ */
+#define BFAD_LUN_QUEUE_DEPTH 32
+#define BFAD_IO_MAX_SGE SG_ALL
+
+#define bfad_isr_t irq_handler_t
+
+#define MAX_MSIX_ENTRY 22
+
+struct bfad_msix_s {
+ struct bfad_s *bfad;
+ struct msix_entry msix;
+};
+
+enum bfad_port_pvb_type {
+ BFAD_PORT_PHYS_BASE = 0,
+ BFAD_PORT_PHYS_VPORT = 1,
+ BFAD_PORT_VF_BASE = 2,
+ BFAD_PORT_VF_VPORT = 3,
+};
+
+/*
+ * PORT data structure
+ */
+struct bfad_port_s {
+ struct list_head list_entry;
+ struct bfad_s *bfad;
+ struct bfa_fcs_port_s *fcs_port;
+ u32 roles;
+ s32 flags;
+ u32 supported_fc4s;
+ u8 ipfc_flags;
+ enum bfad_port_pvb_type pvb_type;
+ struct bfad_im_port_s *im_port; /* IM specific data */
+ struct bfad_tm_port_s *tm_port; /* TM specific data */
+ struct bfad_ipfc_port_s *ipfc_port; /* IPFC specific data */
+};
+
+/*
+ * VPORT data structure
+ */
+struct bfad_vport_s {
+ struct bfad_port_s drv_port;
+ struct bfa_fcs_vport_s fcs_vport;
+ struct completion *comp_del;
+};
+
+/*
+ * VF data structure
+ */
+struct bfad_vf_s {
+ bfa_fcs_vf_t fcs_vf;
+ struct bfad_port_s base_port; /* base port for vf */
+ struct bfad_s *bfad;
+};
+
+struct bfad_cfg_param_s {
+ u32 rport_del_timeout;
+ u32 ioc_queue_depth;
+ u32 lun_queue_depth;
+ u32 io_max_sge;
+ u32 binding_method;
+};
+
+#define BFAD_AEN_MAX_APPS 8
+struct bfad_aen_file_s {
+ struct list_head qe;
+ struct bfad_s *bfad;
+ s32 ri;
+ s32 app_id;
+};
+
+/*
+ * BFAD (PCI function) data structure
+ */
+struct bfad_s {
+ struct list_head list_entry;
+ struct bfa_s bfa;
+ struct bfa_fcs_s bfa_fcs;
+ struct pci_dev *pcidev;
+ const char *pci_name;
+ struct bfa_pcidev_s hal_pcidev;
+ struct bfa_ioc_pci_attr_s pci_attr;
+ unsigned long pci_bar0_map;
+ void __iomem *pci_bar0_kva;
+ struct completion comp;
+ struct completion suspend;
+ struct completion disable_comp;
+ bfa_boolean_t disable_active;
+ struct bfad_port_s pport; /* physical port of the BFAD */
+ struct bfa_meminfo_s meminfo;
+ struct bfa_iocfc_cfg_s ioc_cfg;
+ u32 inst_no; /* BFAD instance number */
+ u32 bfad_flags;
+ spinlock_t bfad_lock;
+ struct bfad_cfg_param_s cfg_data;
+ struct bfad_msix_s msix_tab[MAX_MSIX_ENTRY];
+ int nvec;
+ char adapter_name[BFA_ADAPTER_SYM_NAME_LEN];
+ char port_name[BFA_ADAPTER_SYM_NAME_LEN];
+ struct timer_list hal_tmo;
+ unsigned long hs_start;
+ struct bfad_im_s *im; /* IM specific data */
+ struct bfad_tm_s *tm; /* TM specific data */
+ struct bfad_ipfc_s *ipfc; /* IPFC specific data */
+ struct bfa_log_mod_s log_data;
+ struct bfa_trc_mod_s *trcmod;
+ struct bfa_log_mod_s *logmod;
+ struct bfa_aen_s *aen;
+ struct bfa_aen_s aen_buf;
+ struct bfad_aen_file_s file_buf[BFAD_AEN_MAX_APPS];
+ struct list_head file_q;
+ struct list_head file_free_q;
+ struct bfa_plog_s plog_buf;
+ int ref_count;
+ bfa_boolean_t ipfc_enabled;
+ struct fc_host_statistics link_stats;
+
+ struct kobject *bfa_kobj;
+ struct kobject *ioc_kobj;
+ struct kobject *pport_kobj;
+ struct kobject *lport_kobj;
+};
+
+/*
+ * RPORT data structure
+ */
+struct bfad_rport_s {
+ struct bfa_fcs_rport_s fcs_rport;
+};
+
+struct bfad_buf_info {
+ void *virt;
+ dma_addr_t phys;
+ u32 size;
+};
+
+struct bfad_fcxp {
+ struct bfad_port_s *port;
+ struct bfa_rport_s *bfa_rport;
+ bfa_status_t req_status;
+ u16 tag;
+ u16 rsp_len;
+ u16 rsp_maxlen;
+ u8 use_ireqbuf;
+ u8 use_irspbuf;
+ u32 num_req_sgles;
+ u32 num_rsp_sgles;
+ struct fchs_s fchs;
+ void *reqbuf_info;
+ void *rspbuf_info;
+ struct bfa_sge_s *req_sge;
+ struct bfa_sge_s *rsp_sge;
+ fcxp_send_cb_t send_cbfn;
+ void *send_cbarg;
+ void *bfa_fcxp;
+ struct completion comp;
+};
+
+struct bfad_hal_comp {
+ bfa_status_t status;
+ struct completion comp;
+};
+
+/*
+ * Macro to obtain the immediate lower power
+ * of two for the integer.
+ */
+#define nextLowerInt(x) \
+do { \
+ int j; \
+ (*x)--; \
+ for (j = 1; j < (sizeof(int) * 8); j <<= 1) \
+ (*x) = (*x) | (*x) >> j; \
+ (*x)++; \
+ (*x) = (*x) >> 1; \
+} while (0)
+
+
+bfa_status_t bfad_vport_create(struct bfad_s *bfad, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg);
+bfa_status_t bfad_vf_create(struct bfad_s *bfad, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg);
+bfa_status_t bfad_cfg_pport(struct bfad_s *bfad, enum bfa_port_role role);
+bfa_status_t bfad_drv_init(struct bfad_s *bfad);
+void bfad_drv_start(struct bfad_s *bfad);
+void bfad_uncfg_pport(struct bfad_s *bfad);
+void bfad_drv_stop(struct bfad_s *bfad);
+void bfad_remove_intr(struct bfad_s *bfad);
+void bfad_hal_mem_release(struct bfad_s *bfad);
+void bfad_hcb_comp(void *arg, bfa_status_t status);
+
+int bfad_setup_intr(struct bfad_s *bfad);
+void bfad_remove_intr(struct bfad_s *bfad);
+
+void bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg);
+bfa_status_t bfad_hal_mem_alloc(struct bfad_s *bfad);
+void bfad_bfa_tmo(unsigned long data);
+void bfad_init_timer(struct bfad_s *bfad);
+int bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad);
+void bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad);
+void bfad_fcs_port_cfg(struct bfad_s *bfad);
+void bfad_drv_uninit(struct bfad_s *bfad);
+void bfad_drv_log_level_set(struct bfad_s *bfad);
+bfa_status_t bfad_fc4_module_init(void);
+void bfad_fc4_module_exit(void);
+
+void bfad_pci_remove(struct pci_dev *pdev);
+int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid);
+void bfad_os_rport_online_wait(struct bfad_s *bfad);
+int bfad_os_get_linkup_delay(struct bfad_s *bfad);
+int bfad_install_msix_handler(struct bfad_s *bfad);
+
+extern struct idr bfad_im_port_index;
+extern struct list_head bfad_list;
+extern int bfa_lun_queue_depth;
+extern int bfad_supported_fc4s;
+extern int bfa_linkup_delay;
+
+#endif /* __BFAD_DRV_H__ */
diff --git a/drivers/scsi/bfa/bfad_fwimg.c b/drivers/scsi/bfa/bfad_fwimg.c
new file mode 100644
index 000000000000..2c2082d6ce45
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_fwimg.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfad_fwimg.c Linux driver PCI interface module.
+ */
+#include <bfa_os_inc.h>
+#include <bfad_drv.h>
+#include <bfad_im_compat.h>
+#include <defs/bfa_defs_version.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/fcntl.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <bfa_fwimg_priv.h>
+#include <bfa.h>
+
+u32 bfi_image_ct_size;
+u32 bfi_image_cb_size;
+u32 *bfi_image_ct;
+u32 *bfi_image_cb;
+
+
+#define BFAD_FW_FILE_CT "ctfw.bin"
+#define BFAD_FW_FILE_CB "cbfw.bin"
+
+u32 *
+bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
+ u32 *bfi_image_size, char *fw_name)
+{
+ const struct firmware *fw;
+
+ if (request_firmware(&fw, fw_name, &pdev->dev)) {
+ printk(KERN_ALERT "Can't locate firmware %s\n", fw_name);
+ goto error;
+ }
+
+ *bfi_image = vmalloc(fw->size);
+ if (NULL == *bfi_image) {
+ printk(KERN_ALERT "Fail to allocate buffer for fw image "
+ "size=%x!\n", (u32) fw->size);
+ goto error;
+ }
+
+ memcpy(*bfi_image, fw->data, fw->size);
+ *bfi_image_size = fw->size/sizeof(u32);
+
+ return *bfi_image;
+
+error:
+ return NULL;
+}
+
+u32 *
+bfad_get_firmware_buf(struct pci_dev *pdev)
+{
+ if (pdev->device == BFA_PCI_DEVICE_ID_CT) {
+ 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;
+ } 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;
+ }
+}
+
+u32 *
+bfi_image_ct_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_ct + off); }
+
+u32 *
+bfi_image_cb_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_cb + off); }
+
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
new file mode 100644
index 000000000000..ae3a0689a66f
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -0,0 +1,1230 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfad_im.c Linux driver IM module.
+ */
+
+#include "bfad_drv.h"
+#include "bfad_im.h"
+#include "bfad_trcmod.h"
+#include "bfa_cb_ioim_macros.h"
+#include <fcb/bfa_fcb_fcpim.h>
+
+BFA_TRC_FILE(LDRV, IM);
+
+DEFINE_IDR(bfad_im_port_index);
+struct scsi_transport_template *bfad_im_scsi_transport_template;
+static void bfad_im_itnim_work_handler(struct work_struct *work);
+static int bfad_im_queuecommand(struct scsi_cmnd *cmnd,
+ void (*done)(struct scsi_cmnd *));
+static int bfad_im_slave_alloc(struct scsi_device *sdev);
+
+void
+bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio,
+ enum bfi_ioim_status io_status, u8 scsi_status,
+ int sns_len, u8 *sns_info, s32 residue)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ struct bfad_s *bfad = drv;
+ struct bfad_itnim_data_s *itnim_data;
+ struct bfad_itnim_s *itnim;
+
+ switch (io_status) {
+ case BFI_IOIM_STS_OK:
+ bfa_trc(bfad, scsi_status);
+ cmnd->result = ScsiResult(DID_OK, scsi_status);
+ scsi_set_resid(cmnd, 0);
+
+ if (sns_len > 0) {
+ bfa_trc(bfad, sns_len);
+ if (sns_len > SCSI_SENSE_BUFFERSIZE)
+ sns_len = SCSI_SENSE_BUFFERSIZE;
+ memcpy(cmnd->sense_buffer, sns_info, sns_len);
+ }
+ if (residue > 0)
+ scsi_set_resid(cmnd, residue);
+ break;
+
+ case BFI_IOIM_STS_ABORTED:
+ case BFI_IOIM_STS_TIMEDOUT:
+ case BFI_IOIM_STS_PATHTOV:
+ default:
+ cmnd->result = ScsiResult(DID_ERROR, 0);
+ }
+
+ /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */
+ if (cmnd->device->host != NULL)
+ scsi_dma_unmap(cmnd);
+
+ cmnd->host_scribble = NULL;
+ bfa_trc(bfad, cmnd->result);
+
+ itnim_data = cmnd->device->hostdata;
+ if (itnim_data) {
+ itnim = itnim_data->itnim;
+ if (!cmnd->result && itnim &&
+ (bfa_lun_queue_depth > cmnd->device->queue_depth)) {
+ /* Queue depth adjustment for good status completion */
+ bfad_os_ramp_up_qdepth(itnim, cmnd->device);
+ } else if (cmnd->result == SAM_STAT_TASK_SET_FULL && itnim) {
+ /* qfull handling */
+ bfad_os_handle_qfull(itnim, cmnd->device);
+ }
+ }
+
+ cmnd->scsi_done(cmnd);
+}
+
+void
+bfa_cb_ioim_good_comp(void *drv, struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ struct bfad_itnim_data_s *itnim_data;
+ struct bfad_itnim_s *itnim;
+
+ cmnd->result = ScsiResult(DID_OK, SCSI_STATUS_GOOD);
+
+ /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */
+ if (cmnd->device->host != NULL)
+ scsi_dma_unmap(cmnd);
+
+ cmnd->host_scribble = NULL;
+
+ /* Queue depth adjustment */
+ if (bfa_lun_queue_depth > cmnd->device->queue_depth) {
+ itnim_data = cmnd->device->hostdata;
+ if (itnim_data) {
+ itnim = itnim_data->itnim;
+ if (itnim)
+ bfad_os_ramp_up_qdepth(itnim, cmnd->device);
+ }
+ }
+
+ cmnd->scsi_done(cmnd);
+}
+
+void
+bfa_cb_ioim_abort(void *drv, struct bfad_ioim_s *dio)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio;
+ struct bfad_s *bfad = drv;
+
+ cmnd->result = ScsiResult(DID_ERROR, 0);
+
+ /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */
+ if (cmnd->device->host != NULL)
+ scsi_dma_unmap(cmnd);
+
+ bfa_trc(bfad, cmnd->result);
+ cmnd->host_scribble = NULL;
+}
+
+void
+bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
+ enum bfi_tskim_status tsk_status)
+{
+ struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dtsk;
+ wait_queue_head_t *wq;
+
+ cmnd->SCp.Status |= tsk_status << 1;
+ set_bit(IO_DONE_BIT, (unsigned long *)&cmnd->SCp.Status);
+ wq = (wait_queue_head_t *) cmnd->SCp.ptr;
+ cmnd->SCp.ptr = NULL;
+
+ if (wq)
+ wake_up(wq);
+}
+
+void
+bfa_cb_ioim_resfree(void *drv)
+{
+}
+
+/**
+ * Scsi_Host_template SCSI host template
+ */
+/**
+ * Scsi_Host template entry, returns BFAD PCI info.
+ */
+static const char *
+bfad_im_info(struct Scsi_Host *shost)
+{
+ static char bfa_buf[256];
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfa_ioc_attr_s ioc_attr;
+ struct bfad_s *bfad = im_port->bfad;
+
+ memset(&ioc_attr, 0, sizeof(ioc_attr));
+ bfa_get_attr(&bfad->bfa, &ioc_attr);
+
+ memset(bfa_buf, 0, sizeof(bfa_buf));
+ snprintf(bfa_buf, sizeof(bfa_buf),
+ "Brocade FC/FCOE Adapter, " "model: %s hwpath: %s driver: %s",
+ ioc_attr.adapter_attr.model, bfad->pci_name,
+ BFAD_DRIVER_VERSION);
+ return bfa_buf;
+}
+
+/**
+ * Scsi_Host template entry, aborts the specified SCSI command.
+ *
+ * Returns: SUCCESS or FAILED.
+ */
+static int
+bfad_im_abort_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_ioim_s *hal_io;
+ unsigned long flags;
+ u32 timeout;
+ int rc = FAILED;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ hal_io = (struct bfa_ioim_s *) cmnd->host_scribble;
+ if (!hal_io) {
+ /* IO has been completed, retrun success */
+ rc = SUCCESS;
+ goto out;
+ }
+ if (hal_io->dio != (struct bfad_ioim_s *) cmnd) {
+ rc = FAILED;
+ goto out;
+ }
+
+ bfa_trc(bfad, hal_io->iotag);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_ABORT,
+ im_port->shost->host_no, cmnd, hal_io->iotag);
+ bfa_ioim_abort(hal_io);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ /* Need to wait until the command get aborted */
+ timeout = 10;
+ while ((struct bfa_ioim_s *) cmnd->host_scribble == hal_io) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(timeout);
+ if (timeout < 4 * HZ)
+ timeout *= 2;
+ }
+
+ cmnd->scsi_done(cmnd);
+ bfa_trc(bfad, hal_io->iotag);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_ABORT_COMP,
+ im_port->shost->host_no, cmnd, hal_io->iotag);
+ return SUCCESS;
+out:
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ return rc;
+}
+
+static bfa_status_t
+bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd,
+ struct bfad_itnim_s *itnim)
+{
+ struct bfa_tskim_s *tskim;
+ struct bfa_itnim_s *bfa_itnim;
+ bfa_status_t rc = BFA_STATUS_OK;
+
+ bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
+ if (!tskim) {
+ BFA_DEV_PRINTF(bfad, BFA_ERR,
+ "target reset, fail to allocate tskim\n");
+ rc = BFA_STATUS_FAILED;
+ goto out;
+ }
+
+ /*
+ * Set host_scribble to NULL to avoid aborting a task command if
+ * happens.
+ */
+ cmnd->host_scribble = NULL;
+ cmnd->SCp.Status = 0;
+ bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ bfa_tskim_start(tskim, bfa_itnim, (lun_t)0,
+ FCP_TM_TARGET_RESET, BFAD_TARGET_RESET_TMO);
+out:
+ return rc;
+}
+
+/**
+ * Scsi_Host template entry, resets a LUN and abort its all commands.
+ *
+ * Returns: SUCCESS or FAILED.
+ *
+ */
+static int
+bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_itnim_data_s *itnim_data = cmnd->device->hostdata;
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfa_tskim_s *tskim;
+ struct bfad_itnim_s *itnim;
+ struct bfa_itnim_s *bfa_itnim;
+ DECLARE_WAIT_QUEUE_HEAD(wq);
+ int rc = SUCCESS;
+ unsigned long flags;
+ enum bfi_tskim_status task_status;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ itnim = itnim_data->itnim;
+ if (!itnim) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ rc = FAILED;
+ goto out;
+ }
+
+ tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd);
+ if (!tskim) {
+ BFA_DEV_PRINTF(bfad, BFA_ERR,
+ "LUN reset, fail to allocate tskim");
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ rc = FAILED;
+ goto out;
+ }
+
+ /**
+ * Set host_scribble to NULL to avoid aborting a task command
+ * if happens.
+ */
+ cmnd->host_scribble = NULL;
+ cmnd->SCp.ptr = (char *)&wq;
+ cmnd->SCp.Status = 0;
+ bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim);
+ bfa_tskim_start(tskim, bfa_itnim,
+ bfad_int_to_lun(cmnd->device->lun),
+ FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ wait_event(wq, test_bit(IO_DONE_BIT,
+ (unsigned long *)&cmnd->SCp.Status));
+
+ task_status = cmnd->SCp.Status >> 1;
+ if (task_status != BFI_TSKIM_STS_OK) {
+ BFA_DEV_PRINTF(bfad, BFA_ERR, "LUN reset failure, status: %d\n",
+ task_status);
+ rc = FAILED;
+ }
+
+out:
+ return rc;
+}
+
+/**
+ * Scsi_Host template entry, resets the bus and abort all commands.
+ */
+static int
+bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) shost->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfad_itnim_s *itnim;
+ unsigned long flags;
+ u32 i, rc, err_cnt = 0;
+ DECLARE_WAIT_QUEUE_HEAD(wq);
+ enum bfi_tskim_status task_status;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ for (i = 0; i < MAX_FCP_TARGET; i++) {
+ itnim = bfad_os_get_itnim(im_port, i);
+ if (itnim) {
+ cmnd->SCp.ptr = (char *)&wq;
+ rc = bfad_im_target_reset_send(bfad, cmnd, itnim);
+ if (rc != BFA_STATUS_OK) {
+ err_cnt++;
+ continue;
+ }
+
+ /* wait target reset to complete */
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ wait_event(wq, test_bit(IO_DONE_BIT,
+ (unsigned long *)&cmnd->SCp.Status));
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ task_status = cmnd->SCp.Status >> 1;
+ if (task_status != BFI_TSKIM_STS_OK) {
+ BFA_DEV_PRINTF(bfad, BFA_ERR,
+ "target reset failure,"
+ " status: %d\n", task_status);
+ err_cnt++;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (err_cnt)
+ return FAILED;
+
+ return SUCCESS;
+}
+
+/**
+ * Scsi_Host template entry slave_destroy.
+ */
+static void
+bfad_im_slave_destroy(struct scsi_device *sdev)
+{
+ sdev->hostdata = NULL;
+ return;
+}
+
+/**
+ * BFA FCS itnim callbacks
+ */
+
+/**
+ * BFA FCS itnim alloc callback, after successful PRLI
+ * Context: Interrupt
+ */
+void
+bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim,
+ struct bfad_itnim_s **itnim_drv)
+{
+ *itnim_drv = kzalloc(sizeof(struct bfad_itnim_s), GFP_ATOMIC);
+ if (*itnim_drv == NULL)
+ return;
+
+ (*itnim_drv)->im = bfad->im;
+ *itnim = &(*itnim_drv)->fcs_itnim;
+ (*itnim_drv)->state = ITNIM_STATE_NONE;
+
+ /*
+ * Initiaze the itnim_work
+ */
+ INIT_WORK(&(*itnim_drv)->itnim_work, bfad_im_itnim_work_handler);
+ bfad->bfad_flags |= BFAD_RPORT_ONLINE;
+}
+
+/**
+ * BFA FCS itnim free callback.
+ * Context: Interrupt. bfad_lock is held
+ */
+void
+bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv)
+{
+ struct bfad_port_s *port;
+ wwn_t wwpn;
+ u32 fcid;
+ char wwpn_str[32], fcid_str[16];
+
+ /* online to free state transtion should not happen */
+ bfa_assert(itnim_drv->state != ITNIM_STATE_ONLINE);
+
+ itnim_drv->queue_work = 1;
+ /* offline request is not yet done, use the same request to free */
+ if (itnim_drv->state == ITNIM_STATE_OFFLINE_PENDING)
+ itnim_drv->queue_work = 0;
+
+ itnim_drv->state = ITNIM_STATE_FREE;
+ port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim);
+ itnim_drv->im_port = port->im_port;
+ wwpn = bfa_fcs_itnim_get_pwwn(&itnim_drv->fcs_itnim);
+ fcid = bfa_fcs_itnim_get_fcid(&itnim_drv->fcs_itnim);
+ wwn2str(wwpn_str, wwpn);
+ fcid2str(fcid_str, fcid);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_FREE,
+ port->im_port->shost->host_no,
+ fcid_str, wwpn_str);
+ bfad_os_itnim_process(itnim_drv);
+}
+
+/**
+ * BFA FCS itnim online callback.
+ * Context: Interrupt. bfad_lock is held
+ */
+void
+bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv)
+{
+ struct bfad_port_s *port;
+
+ itnim_drv->bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim_drv->fcs_itnim);
+ port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim);
+ itnim_drv->state = ITNIM_STATE_ONLINE;
+ itnim_drv->queue_work = 1;
+ itnim_drv->im_port = port->im_port;
+ bfad_os_itnim_process(itnim_drv);
+}
+
+/**
+ * BFA FCS itnim offline callback.
+ * Context: Interrupt. bfad_lock is held
+ */
+void
+bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv)
+{
+ struct bfad_port_s *port;
+ struct bfad_s *bfad;
+
+ port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim);
+ bfad = port->bfad;
+ if ((bfad->pport.flags & BFAD_PORT_DELETE) ||
+ (port->flags & BFAD_PORT_DELETE)) {
+ itnim_drv->state = ITNIM_STATE_OFFLINE;
+ return;
+ }
+ itnim_drv->im_port = port->im_port;
+ itnim_drv->state = ITNIM_STATE_OFFLINE_PENDING;
+ itnim_drv->queue_work = 1;
+ bfad_os_itnim_process(itnim_drv);
+}
+
+/**
+ * BFA FCS itnim timeout callback.
+ * Context: Interrupt. bfad_lock is held
+ */
+void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim)
+{
+ itnim->state = ITNIM_STATE_TIMEOUT;
+}
+
+/**
+ * Path TOV processing begin notification -- dummy for linux
+ */
+void
+bfa_fcb_itnim_tov_begin(struct bfad_itnim_s *itnim)
+{
+}
+
+
+
+/**
+ * Allocate a Scsi_Host for a port.
+ */
+int
+bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
+{
+ int error = 1;
+
+ if (!idr_pre_get(&bfad_im_port_index, GFP_KERNEL)) {
+ printk(KERN_WARNING "idr_pre_get failure\n");
+ goto out;
+ }
+
+ error = idr_get_new(&bfad_im_port_index, im_port,
+ &im_port->idr_id);
+ if (error) {
+ printk(KERN_WARNING "idr_get_new failure\n");
+ goto out;
+ }
+
+ im_port->shost = bfad_os_scsi_host_alloc(im_port, bfad);
+ if (!im_port->shost) {
+ error = 1;
+ goto out_free_idr;
+ }
+
+ im_port->shost->hostdata[0] = (unsigned long)im_port;
+ im_port->shost->unique_id = im_port->idr_id;
+ im_port->shost->this_id = -1;
+ im_port->shost->max_id = MAX_FCP_TARGET;
+ im_port->shost->max_lun = MAX_FCP_LUN;
+ im_port->shost->max_cmd_len = 16;
+ im_port->shost->can_queue = bfad->cfg_data.ioc_queue_depth;
+ im_port->shost->transportt = bfad_im_scsi_transport_template;
+
+ error = bfad_os_scsi_add_host(im_port->shost, im_port, bfad);
+ if (error) {
+ printk(KERN_WARNING "bfad_os_scsi_add_host failure %d\n",
+ error);
+ goto out_fc_rel;
+ }
+
+ /* setup host fixed attribute if the lk supports */
+ bfad_os_fc_host_init(im_port);
+
+ return 0;
+
+out_fc_rel:
+ scsi_host_put(im_port->shost);
+out_free_idr:
+ idr_remove(&bfad_im_port_index, im_port->idr_id);
+out:
+ return error;
+}
+
+void
+bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
+{
+ unsigned long flags;
+
+ bfa_trc(bfad, bfad->inst_no);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_SCSI_HOST_FREE,
+ im_port->shost->host_no);
+
+ fc_remove_host(im_port->shost);
+
+ scsi_remove_host(im_port->shost);
+ scsi_host_put(im_port->shost);
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ idr_remove(&bfad_im_port_index, im_port->idr_id);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+static void
+bfad_im_port_delete_handler(struct work_struct *work)
+{
+ struct bfad_im_port_s *im_port =
+ container_of(work, struct bfad_im_port_s, port_delete_work);
+
+ bfad_im_scsi_host_free(im_port->bfad, im_port);
+ bfad_im_port_clean(im_port);
+ kfree(im_port);
+}
+
+bfa_status_t
+bfad_im_port_new(struct bfad_s *bfad, struct bfad_port_s *port)
+{
+ int rc = BFA_STATUS_OK;
+ struct bfad_im_port_s *im_port;
+
+ im_port = kzalloc(sizeof(struct bfad_im_port_s), GFP_ATOMIC);
+ if (im_port == NULL) {
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+ port->im_port = im_port;
+ im_port->port = port;
+ im_port->bfad = bfad;
+
+ INIT_WORK(&im_port->port_delete_work, bfad_im_port_delete_handler);
+ INIT_LIST_HEAD(&im_port->itnim_mapped_list);
+ INIT_LIST_HEAD(&im_port->binding_list);
+
+ext:
+ return rc;
+}
+
+void
+bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port)
+{
+ struct bfad_im_port_s *im_port = port->im_port;
+
+ queue_work(bfad->im->drv_workq,
+ &im_port->port_delete_work);
+}
+
+void
+bfad_im_port_clean(struct bfad_im_port_s *im_port)
+{
+ struct bfad_fcp_binding *bp, *bp_new;
+ unsigned long flags;
+ struct bfad_s *bfad = im_port->bfad;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ list_for_each_entry_safe(bp, bp_new, &im_port->binding_list,
+ list_entry) {
+ list_del(&bp->list_entry);
+ kfree(bp);
+ }
+
+ /* the itnim_mapped_list must be empty at this time */
+ bfa_assert(list_empty(&im_port->itnim_mapped_list));
+
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+void
+bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port)
+{
+}
+
+void
+bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port)
+{
+}
+
+bfa_status_t
+bfad_im_probe(struct bfad_s *bfad)
+{
+ struct bfad_im_s *im;
+ bfa_status_t rc = BFA_STATUS_OK;
+
+ im = kzalloc(sizeof(struct bfad_im_s), GFP_KERNEL);
+ if (im == NULL) {
+ rc = BFA_STATUS_ENOMEM;
+ goto ext;
+ }
+
+ bfad->im = im;
+ im->bfad = bfad;
+
+ if (bfad_os_thread_workq(bfad) != BFA_STATUS_OK) {
+ kfree(im);
+ rc = BFA_STATUS_FAILED;
+ }
+
+ext:
+ return rc;
+}
+
+void
+bfad_im_probe_undo(struct bfad_s *bfad)
+{
+ if (bfad->im) {
+ bfad_os_destroy_workq(bfad->im);
+ kfree(bfad->im);
+ bfad->im = NULL;
+ }
+}
+
+
+
+
+int
+bfad_os_scsi_add_host(struct Scsi_Host *shost, struct bfad_im_port_s *im_port,
+ struct bfad_s *bfad)
+{
+ struct device *dev;
+
+ if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
+ dev = &bfad->pcidev->dev;
+ else
+ dev = &bfad->pport.im_port->shost->shost_gendev;
+
+ return scsi_add_host(shost, dev);
+}
+
+struct Scsi_Host *
+bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad)
+{
+ struct scsi_host_template *sht;
+
+ if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE)
+ sht = &bfad_im_scsi_host_template;
+ else
+ sht = &bfad_im_vport_template;
+
+ sht->sg_tablesize = bfad->cfg_data.io_max_sge;
+
+ return scsi_host_alloc(sht, sizeof(unsigned long));
+}
+
+void
+bfad_os_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port)
+{
+ flush_workqueue(bfad->im->drv_workq);
+ bfad_im_scsi_host_free(im_port->bfad, im_port);
+ bfad_im_port_clean(im_port);
+ kfree(im_port);
+}
+
+void
+bfad_os_destroy_workq(struct bfad_im_s *im)
+{
+ if (im && im->drv_workq) {
+ destroy_workqueue(im->drv_workq);
+ im->drv_workq = NULL;
+ }
+}
+
+bfa_status_t
+bfad_os_thread_workq(struct bfad_s *bfad)
+{
+ struct bfad_im_s *im = bfad->im;
+
+ bfa_trc(bfad, 0);
+ snprintf(im->drv_workq_name, BFAD_KOBJ_NAME_LEN, "bfad_wq_%d",
+ bfad->inst_no);
+ im->drv_workq = create_singlethread_workqueue(im->drv_workq_name);
+ if (!im->drv_workq)
+ return BFA_STATUS_FAILED;
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Scsi_Host template entry.
+ *
+ * Description:
+ * OS entry point to adjust the queue_depths on a per-device basis.
+ * Called once per device during the bus scan.
+ * Return non-zero if fails.
+ */
+static int
+bfad_im_slave_configure(struct scsi_device *sdev)
+{
+ if (sdev->tagged_supported)
+ scsi_activate_tcq(sdev, bfa_lun_queue_depth);
+ else
+ scsi_deactivate_tcq(sdev, bfa_lun_queue_depth);
+
+ return 0;
+}
+
+struct scsi_host_template bfad_im_scsi_host_template = {
+ .module = THIS_MODULE,
+ .name = BFAD_DRIVER_NAME,
+ .info = bfad_im_info,
+ .queuecommand = bfad_im_queuecommand,
+ .eh_abort_handler = bfad_im_abort_handler,
+ .eh_device_reset_handler = bfad_im_reset_lun_handler,
+ .eh_bus_reset_handler = bfad_im_reset_bus_handler,
+
+ .slave_alloc = bfad_im_slave_alloc,
+ .slave_configure = bfad_im_slave_configure,
+ .slave_destroy = bfad_im_slave_destroy,
+
+ .this_id = -1,
+ .sg_tablesize = BFAD_IO_MAX_SGE,
+ .cmd_per_lun = 3,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = bfad_im_host_attrs,
+ .max_sectors = 0xFFFF,
+};
+
+struct scsi_host_template bfad_im_vport_template = {
+ .module = THIS_MODULE,
+ .name = BFAD_DRIVER_NAME,
+ .info = bfad_im_info,
+ .queuecommand = bfad_im_queuecommand,
+ .eh_abort_handler = bfad_im_abort_handler,
+ .eh_device_reset_handler = bfad_im_reset_lun_handler,
+ .eh_bus_reset_handler = bfad_im_reset_bus_handler,
+
+ .slave_alloc = bfad_im_slave_alloc,
+ .slave_configure = bfad_im_slave_configure,
+ .slave_destroy = bfad_im_slave_destroy,
+
+ .this_id = -1,
+ .sg_tablesize = BFAD_IO_MAX_SGE,
+ .cmd_per_lun = 3,
+ .use_clustering = ENABLE_CLUSTERING,
+ .shost_attrs = bfad_im_vport_attrs,
+ .max_sectors = 0xFFFF,
+};
+
+void
+bfad_im_probe_post(struct bfad_im_s *im)
+{
+ flush_workqueue(im->drv_workq);
+}
+
+bfa_status_t
+bfad_im_module_init(void)
+{
+ bfad_im_scsi_transport_template =
+ fc_attach_transport(&bfad_im_fc_function_template);
+ if (!bfad_im_scsi_transport_template)
+ return BFA_STATUS_ENOMEM;
+
+ return BFA_STATUS_OK;
+}
+
+void
+bfad_im_module_exit(void)
+{
+ if (bfad_im_scsi_transport_template)
+ fc_release_transport(bfad_im_scsi_transport_template);
+}
+
+void
+bfad_os_itnim_process(struct bfad_itnim_s *itnim_drv)
+{
+ struct bfad_im_s *im = itnim_drv->im;
+
+ if (itnim_drv->queue_work)
+ queue_work(im->drv_workq, &itnim_drv->itnim_work);
+}
+
+void
+bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
+{
+ struct scsi_device *tmp_sdev;
+
+ if (((jiffies - itnim->last_ramp_up_time) >
+ BFA_QUEUE_FULL_RAMP_UP_TIME * HZ) &&
+ ((jiffies - itnim->last_queue_full_time) >
+ BFA_QUEUE_FULL_RAMP_UP_TIME * HZ)) {
+ shost_for_each_device(tmp_sdev, sdev->host) {
+ if (bfa_lun_queue_depth > tmp_sdev->queue_depth) {
+ if (tmp_sdev->id != sdev->id)
+ continue;
+ if (tmp_sdev->ordered_tags)
+ scsi_adjust_queue_depth(tmp_sdev,
+ MSG_ORDERED_TAG,
+ tmp_sdev->queue_depth + 1);
+ else
+ scsi_adjust_queue_depth(tmp_sdev,
+ MSG_SIMPLE_TAG,
+ tmp_sdev->queue_depth + 1);
+
+ itnim->last_ramp_up_time = jiffies;
+ }
+ }
+ }
+}
+
+void
+bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
+{
+ struct scsi_device *tmp_sdev;
+
+ itnim->last_queue_full_time = jiffies;
+
+ shost_for_each_device(tmp_sdev, sdev->host) {
+ if (tmp_sdev->id != sdev->id)
+ continue;
+ scsi_track_queue_full(tmp_sdev, tmp_sdev->queue_depth - 1);
+ }
+}
+
+
+
+
+struct bfad_itnim_s *
+bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id)
+{
+ struct bfad_itnim_s *itnim = NULL;
+
+ /* Search the mapped list for this target ID */
+ list_for_each_entry(itnim, &im_port->itnim_mapped_list, list_entry) {
+ if (id == itnim->scsi_tgt_id)
+ return itnim;
+ }
+
+ return NULL;
+}
+
+/**
+ * Scsi_Host template entry slave_alloc
+ */
+static int
+bfad_im_slave_alloc(struct scsi_device *sdev)
+{
+ struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
+
+ if (!rport || fc_remote_port_chkready(rport))
+ return -ENXIO;
+
+ sdev->hostdata = rport->dd_data;
+
+ return 0;
+}
+
+void
+bfad_os_fc_host_init(struct bfad_im_port_s *im_port)
+{
+ struct Scsi_Host *host = im_port->shost;
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfad_port_s *port = im_port->port;
+ union attr {
+ struct bfa_pport_attr_s pattr;
+ struct bfa_ioc_attr_s ioc_attr;
+ } attr;
+
+ fc_host_node_name(host) =
+ bfa_os_htonll((bfa_fcs_port_get_nwwn(port->fcs_port)));
+ fc_host_port_name(host) =
+ bfa_os_htonll((bfa_fcs_port_get_pwwn(port->fcs_port)));
+
+ fc_host_supported_classes(host) = FC_COS_CLASS3;
+
+ memset(fc_host_supported_fc4s(host), 0,
+ sizeof(fc_host_supported_fc4s(host)));
+ if (bfad_supported_fc4s & (BFA_PORT_ROLE_FCP_IM | BFA_PORT_ROLE_FCP_TM))
+ /* For FCP type 0x08 */
+ fc_host_supported_fc4s(host)[2] = 1;
+ if (bfad_supported_fc4s | BFA_PORT_ROLE_FCP_IPFC)
+ /* For LLC/SNAP type 0x05 */
+ fc_host_supported_fc4s(host)[3] = 0x20;
+ /* For fibre channel services type 0x20 */
+ fc_host_supported_fc4s(host)[7] = 1;
+
+ memset(&attr.ioc_attr, 0, sizeof(attr.ioc_attr));
+ bfa_get_attr(&bfad->bfa, &attr.ioc_attr);
+ sprintf(fc_host_symbolic_name(host), "Brocade %s FV%s DV%s",
+ attr.ioc_attr.adapter_attr.model,
+ attr.ioc_attr.adapter_attr.fw_ver, BFAD_DRIVER_VERSION);
+
+ fc_host_supported_speeds(host) = 0;
+ fc_host_supported_speeds(host) |=
+ FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT |
+ FC_PORTSPEED_1GBIT;
+
+ memset(&attr.pattr, 0, sizeof(attr.pattr));
+ bfa_pport_get_attr(&bfad->bfa, &attr.pattr);
+ fc_host_maxframe_size(host) = attr.pattr.pport_cfg.maxfrsize;
+}
+
+static void
+bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim)
+{
+ struct fc_rport_identifiers rport_ids;
+ struct fc_rport *fc_rport;
+ struct bfad_itnim_data_s *itnim_data;
+
+ rport_ids.node_name =
+ bfa_os_htonll(bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim));
+ rport_ids.port_name =
+ bfa_os_htonll(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
+ rport_ids.port_id =
+ bfa_os_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim));
+ rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
+
+ itnim->fc_rport = fc_rport =
+ fc_remote_port_add(im_port->shost, 0, &rport_ids);
+
+ if (!fc_rport)
+ return;
+
+ fc_rport->maxframe_size =
+ bfa_fcs_itnim_get_maxfrsize(&itnim->fcs_itnim);
+ fc_rport->supported_classes = bfa_fcs_itnim_get_cos(&itnim->fcs_itnim);
+
+ itnim_data = fc_rport->dd_data;
+ itnim_data->itnim = itnim;
+
+ rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
+
+ if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN)
+ fc_remote_port_rolechg(fc_rport, rport_ids.roles);
+
+ if ((fc_rport->scsi_target_id != -1)
+ && (fc_rport->scsi_target_id < MAX_FCP_TARGET))
+ itnim->scsi_tgt_id = fc_rport->scsi_target_id;
+
+ return;
+}
+
+/**
+ * Work queue handler using FC transport service
+* Context: kernel
+ */
+static void
+bfad_im_itnim_work_handler(struct work_struct *work)
+{
+ struct bfad_itnim_s *itnim = container_of(work, struct bfad_itnim_s,
+ itnim_work);
+ struct bfad_im_s *im = itnim->im;
+ struct bfad_s *bfad = im->bfad;
+ struct bfad_im_port_s *im_port;
+ unsigned long flags;
+ struct fc_rport *fc_rport;
+ wwn_t wwpn;
+ u32 fcid;
+ char wwpn_str[32], fcid_str[16];
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ im_port = itnim->im_port;
+ bfa_trc(bfad, itnim->state);
+ switch (itnim->state) {
+ case ITNIM_STATE_ONLINE:
+ if (!itnim->fc_rport) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ bfad_im_fc_rport_add(im_port, itnim);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ wwpn = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim);
+ fcid = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim);
+ wwn2str(wwpn_str, wwpn);
+ fcid2str(fcid_str, fcid);
+ list_add_tail(&itnim->list_entry,
+ &im_port->itnim_mapped_list);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_ONLINE,
+ im_port->shost->host_no,
+ itnim->scsi_tgt_id,
+ fcid_str, wwpn_str);
+ } else {
+ printk(KERN_WARNING
+ "%s: itnim %llx is already in online state\n",
+ __func__,
+ bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim));
+ }
+
+ break;
+ case ITNIM_STATE_OFFLINE_PENDING:
+ itnim->state = ITNIM_STATE_OFFLINE;
+ if (itnim->fc_rport) {
+ fc_rport = itnim->fc_rport;
+ ((struct bfad_itnim_data_s *)
+ fc_rport->dd_data)->itnim = NULL;
+ itnim->fc_rport = NULL;
+ if (!(im_port->port->flags & BFAD_PORT_DELETE)) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ fc_rport->dev_loss_tmo =
+ bfa_fcpim_path_tov_get(&bfad->bfa) + 1;
+ fc_remote_port_delete(fc_rport);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ }
+ wwpn = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim);
+ fcid = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim);
+ wwn2str(wwpn_str, wwpn);
+ fcid2str(fcid_str, fcid);
+ list_del(&itnim->list_entry);
+ bfa_log(bfad->logmod, BFA_LOG_LINUX_ITNIM_OFFLINE,
+ im_port->shost->host_no,
+ itnim->scsi_tgt_id,
+ fcid_str, wwpn_str);
+ }
+ break;
+ case ITNIM_STATE_FREE:
+ if (itnim->fc_rport) {
+ fc_rport = itnim->fc_rport;
+ ((struct bfad_itnim_data_s *)
+ fc_rport->dd_data)->itnim = NULL;
+ itnim->fc_rport = NULL;
+ if (!(im_port->port->flags & BFAD_PORT_DELETE)) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ fc_rport->dev_loss_tmo =
+ bfa_fcpim_path_tov_get(&bfad->bfa) + 1;
+ fc_remote_port_delete(fc_rport);
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ }
+ list_del(&itnim->list_entry);
+ }
+
+ kfree(itnim);
+ break;
+ default:
+ bfa_assert(0);
+ break;
+ }
+
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+}
+
+/**
+ * Scsi_Host template entry, queue a SCSI command to the BFAD.
+ */
+static int
+bfad_im_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *))
+{
+ struct bfad_im_port_s *im_port =
+ (struct bfad_im_port_s *) cmnd->device->host->hostdata[0];
+ struct bfad_s *bfad = im_port->bfad;
+ struct bfad_itnim_data_s *itnim_data = cmnd->device->hostdata;
+ struct bfad_itnim_s *itnim;
+ struct bfa_ioim_s *hal_io;
+ unsigned long flags;
+ int rc;
+ s16 sg_cnt = 0;
+ struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
+
+ rc = fc_remote_port_chkready(rport);
+ if (rc) {
+ cmnd->result = rc;
+ done(cmnd);
+ return 0;
+ }
+
+ sg_cnt = scsi_dma_map(cmnd);
+
+ if (sg_cnt < 0)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ cmnd->scsi_done = done;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ if (!(bfad->bfad_flags & BFAD_HAL_START_DONE)) {
+ printk(KERN_WARNING
+ "bfad%d, queuecommand %p %x failed, BFA stopped\n",
+ bfad->inst_no, cmnd, cmnd->cmnd[0]);
+ cmnd->result = ScsiResult(DID_NO_CONNECT, 0);
+ goto out_fail_cmd;
+ }
+
+ itnim = itnim_data->itnim;
+ if (!itnim) {
+ cmnd->result = ScsiResult(DID_IMM_RETRY, 0);
+ goto out_fail_cmd;
+ }
+
+ hal_io = bfa_ioim_alloc(&bfad->bfa, (struct bfad_ioim_s *) cmnd,
+ itnim->bfa_itnim, sg_cnt);
+ if (!hal_io) {
+ printk(KERN_WARNING "hal_io failure\n");
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ scsi_dma_unmap(cmnd);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ cmnd->host_scribble = (char *)hal_io;
+ bfa_trc_fp(bfad, hal_io->iotag);
+ bfa_ioim_start(hal_io);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ return 0;
+
+out_fail_cmd:
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ scsi_dma_unmap(cmnd);
+ if (done)
+ done(cmnd);
+
+ return 0;
+}
+
+void
+bfad_os_rport_online_wait(struct bfad_s *bfad)
+{
+ int i;
+ int rport_delay = 10;
+
+ for (i = 0; !(bfad->bfad_flags & BFAD_PORT_ONLINE)
+ && i < bfa_linkup_delay; i++)
+ schedule_timeout_uninterruptible(HZ);
+
+ if (bfad->bfad_flags & BFAD_PORT_ONLINE) {
+ rport_delay = rport_delay < bfa_linkup_delay ?
+ rport_delay : bfa_linkup_delay;
+ for (i = 0; !(bfad->bfad_flags & BFAD_RPORT_ONLINE)
+ && i < rport_delay; i++)
+ schedule_timeout_uninterruptible(HZ);
+
+ if (rport_delay > 0 && (bfad->bfad_flags & BFAD_RPORT_ONLINE))
+ schedule_timeout_uninterruptible(rport_delay * HZ);
+ }
+}
+
+int
+bfad_os_get_linkup_delay(struct bfad_s *bfad)
+{
+
+ u8 nwwns = 0;
+ wwn_t *wwns;
+ int ldelay;
+
+ /*
+ * Querying for the boot target port wwns
+ * -- read from boot information in flash.
+ * If nwwns > 0 => boot over SAN and set bfa_linkup_delay = 30
+ * else => local boot machine set bfa_linkup_delay = 10
+ */
+
+ bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, &wwns);
+
+ if (nwwns > 0) {
+ /* If boot over SAN; linkup_delay = 30sec */
+ ldelay = 30;
+ } else {
+ /* If local boot; linkup_delay = 10sec */
+ ldelay = 0;
+ }
+
+ return ldelay;
+}
+
+
diff --git a/drivers/scsi/bfa/bfad_im.h b/drivers/scsi/bfa/bfad_im.h
new file mode 100644
index 000000000000..189a5b29e21a
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_im.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFAD_IM_H__
+#define __BFAD_IM_H__
+
+#include "fcs/bfa_fcs_fcpim.h"
+#include "bfad_im_compat.h"
+
+#define FCPI_NAME " fcpim"
+
+void bfad_flags_set(struct bfad_s *bfad, u32 flags);
+bfa_status_t bfad_im_module_init(void);
+void bfad_im_module_exit(void);
+bfa_status_t bfad_im_probe(struct bfad_s *bfad);
+void bfad_im_probe_undo(struct bfad_s *bfad);
+void bfad_im_probe_post(struct bfad_im_s *im);
+bfa_status_t bfad_im_port_new(struct bfad_s *bfad, struct bfad_port_s *port);
+void bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port);
+void bfad_im_port_online(struct bfad_s *bfad, struct bfad_port_s *port);
+void bfad_im_port_offline(struct bfad_s *bfad, struct bfad_port_s *port);
+void bfad_im_port_clean(struct bfad_im_port_s *im_port);
+int bfad_im_scsi_host_alloc(struct bfad_s *bfad,
+ struct bfad_im_port_s *im_port);
+void bfad_im_scsi_host_free(struct bfad_s *bfad,
+ struct bfad_im_port_s *im_port);
+
+#define MAX_FCP_TARGET 1024
+#define MAX_FCP_LUN 16384
+#define BFAD_TARGET_RESET_TMO 60
+#define BFAD_LUN_RESET_TMO 60
+#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
+#define BFA_QUEUE_FULL_RAMP_UP_TIME 120
+#define BFAD_KOBJ_NAME_LEN 20
+
+/*
+ * itnim flags
+ */
+#define ITNIM_MAPPED 0x00000001
+
+#define SCSI_TASK_MGMT 0x00000001
+#define IO_DONE_BIT 0
+
+struct bfad_itnim_data_s {
+ struct bfad_itnim_s *itnim;
+};
+
+struct bfad_im_port_s {
+ struct bfad_s *bfad;
+ struct bfad_port_s *port;
+ struct work_struct port_delete_work;
+ int idr_id;
+ u16 cur_scsi_id;
+ struct list_head binding_list;
+ struct Scsi_Host *shost;
+ struct list_head itnim_mapped_list;
+};
+
+enum bfad_itnim_state {
+ ITNIM_STATE_NONE,
+ ITNIM_STATE_ONLINE,
+ ITNIM_STATE_OFFLINE_PENDING,
+ ITNIM_STATE_OFFLINE,
+ ITNIM_STATE_TIMEOUT,
+ ITNIM_STATE_FREE,
+};
+
+/*
+ * Per itnim data structure
+ */
+struct bfad_itnim_s {
+ struct list_head list_entry;
+ struct bfa_fcs_itnim_s fcs_itnim;
+ struct work_struct itnim_work;
+ u32 flags;
+ enum bfad_itnim_state state;
+ struct bfad_im_s *im;
+ struct bfad_im_port_s *im_port;
+ struct bfad_rport_s *drv_rport;
+ struct fc_rport *fc_rport;
+ struct bfa_itnim_s *bfa_itnim;
+ u16 scsi_tgt_id;
+ u16 queue_work;
+ unsigned long last_ramp_up_time;
+ unsigned long last_queue_full_time;
+};
+
+enum bfad_binding_type {
+ FCP_PWWN_BINDING = 0x1,
+ FCP_NWWN_BINDING = 0x2,
+ FCP_FCID_BINDING = 0x3,
+};
+
+struct bfad_fcp_binding {
+ struct list_head list_entry;
+ enum bfad_binding_type binding_type;
+ u16 scsi_target_id;
+ u32 fc_id;
+ wwn_t nwwn;
+ wwn_t pwwn;
+};
+
+struct bfad_im_s {
+ struct bfad_s *bfad;
+ struct workqueue_struct *drv_workq;
+ char drv_workq_name[BFAD_KOBJ_NAME_LEN];
+};
+
+struct Scsi_Host *bfad_os_scsi_host_alloc(struct bfad_im_port_s *im_port,
+ struct bfad_s *);
+bfa_status_t bfad_os_thread_workq(struct bfad_s *bfad);
+void bfad_os_destroy_workq(struct bfad_im_s *im);
+void bfad_os_itnim_process(struct bfad_itnim_s *itnim_drv);
+void bfad_os_fc_host_init(struct bfad_im_port_s *im_port);
+void bfad_os_init_work(struct bfad_im_port_s *im_port);
+void bfad_os_scsi_host_free(struct bfad_s *bfad,
+ struct bfad_im_port_s *im_port);
+void bfad_os_ramp_up_qdepth(struct bfad_itnim_s *itnim,
+ struct scsi_device *sdev);
+void bfad_os_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev);
+struct bfad_itnim_s *bfad_os_get_itnim(struct bfad_im_port_s *im_port, int id);
+int bfad_os_scsi_add_host(struct Scsi_Host *shost,
+ struct bfad_im_port_s *im_port, struct bfad_s *bfad);
+
+/*
+ * scsi_host_template entries
+ */
+void bfad_im_itnim_unmap(struct bfad_im_port_s *im_port,
+ struct bfad_itnim_s *itnim);
+
+extern struct scsi_host_template bfad_im_scsi_host_template;
+extern struct scsi_host_template bfad_im_vport_template;
+extern struct fc_function_template bfad_im_fc_function_template;
+extern struct scsi_transport_template *bfad_im_scsi_transport_template;
+
+#endif
diff --git a/drivers/scsi/bfa/bfad_im_compat.h b/drivers/scsi/bfa/bfad_im_compat.h
new file mode 100644
index 000000000000..b36be15044a4
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_im_compat.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFAD_IM_COMPAT_H__
+#define __BFAD_IM_COMPAT_H__
+
+extern u32 *bfi_image_buf;
+extern u32 bfi_image_size;
+
+extern struct device_attribute *bfad_im_host_attrs[];
+extern struct device_attribute *bfad_im_vport_attrs[];
+
+u32 *bfad_get_firmware_buf(struct pci_dev *pdev);
+u32 *bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
+ u32 *bfi_image_size, char *fw_name);
+
+static inline u32 *
+bfad_load_fwimg(struct pci_dev *pdev)
+{
+ return bfad_get_firmware_buf(pdev);
+}
+
+static inline void
+bfad_free_fwimg(void)
+{
+ if (bfi_image_ct_size && bfi_image_ct)
+ vfree(bfi_image_ct);
+ if (bfi_image_cb_size && bfi_image_cb)
+ vfree(bfi_image_cb);
+}
+
+#endif
diff --git a/drivers/scsi/bfa/bfad_intr.c b/drivers/scsi/bfa/bfad_intr.c
new file mode 100644
index 000000000000..7de8832f6fee
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_intr.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include "bfad_drv.h"
+#include "bfad_trcmod.h"
+
+BFA_TRC_FILE(LDRV, INTR);
+
+/**
+ * bfa_isr BFA driver interrupt functions
+ */
+static int msix_disable;
+module_param(msix_disable, int, S_IRUGO | S_IWUSR);
+/**
+ * Line based interrupt handler.
+ */
+static irqreturn_t
+bfad_intx(int irq, void *dev_id)
+{
+ struct bfad_s *bfad = dev_id;
+ struct list_head doneq;
+ unsigned long flags;
+ bfa_boolean_t rc;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ rc = bfa_intx(&bfad->bfa);
+ if (!rc) {
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ return IRQ_NONE;
+ }
+
+ bfa_comp_deq(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (!list_empty(&doneq)) {
+ bfa_comp_process(&bfad->bfa, &doneq);
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_comp_free(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ bfa_trc_fp(bfad, irq);
+ }
+
+ return IRQ_HANDLED;
+
+}
+
+static irqreturn_t
+bfad_msix(int irq, void *dev_id)
+{
+ struct bfad_msix_s *vec = dev_id;
+ struct bfad_s *bfad = vec->bfad;
+ struct list_head doneq;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+
+ bfa_msix(&bfad->bfa, vec->msix.entry);
+ bfa_comp_deq(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+
+ if (!list_empty(&doneq)) {
+ bfa_comp_process(&bfad->bfa, &doneq);
+
+ spin_lock_irqsave(&bfad->bfad_lock, flags);
+ bfa_comp_free(&bfad->bfa, &doneq);
+ spin_unlock_irqrestore(&bfad->bfad_lock, flags);
+ }
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * Initialize the MSIX entry table.
+ */
+static void
+bfad_init_msix_entry(struct bfad_s *bfad, struct msix_entry *msix_entries,
+ int mask, int max_bit)
+{
+ int i;
+ int match = 0x00000001;
+
+ for (i = 0, bfad->nvec = 0; i < MAX_MSIX_ENTRY; i++) {
+ if (mask & match) {
+ bfad->msix_tab[bfad->nvec].msix.entry = i;
+ bfad->msix_tab[bfad->nvec].bfad = bfad;
+ msix_entries[bfad->nvec].entry = i;
+ bfad->nvec++;
+ }
+
+ match <<= 1;
+ }
+
+}
+
+int
+bfad_install_msix_handler(struct bfad_s *bfad)
+{
+ int i, error = 0;
+
+ for (i = 0; i < bfad->nvec; i++) {
+ error = request_irq(bfad->msix_tab[i].msix.vector,
+ (irq_handler_t) bfad_msix, 0,
+ BFAD_DRIVER_NAME, &bfad->msix_tab[i]);
+ bfa_trc(bfad, i);
+ bfa_trc(bfad, bfad->msix_tab[i].msix.vector);
+ if (error) {
+ int j;
+
+ for (j = 0; j < i; j++)
+ free_irq(bfad->msix_tab[j].msix.vector,
+ &bfad->msix_tab[j]);
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Setup MSIX based interrupt.
+ */
+int
+bfad_setup_intr(struct bfad_s *bfad)
+{
+ int error = 0;
+ u32 mask = 0, i, num_bit = 0, max_bit = 0;
+ struct msix_entry msix_entries[MAX_MSIX_ENTRY];
+
+ /* Call BFA to get the msix map for this PCI function. */
+ bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit);
+
+ /* Set up the msix entry table */
+ bfad_init_msix_entry(bfad, msix_entries, mask, max_bit);
+
+ if (!msix_disable) {
+ error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec);
+ if (error) {
+ /*
+ * Only error number of vector is available.
+ * We don't have a mechanism to map multiple
+ * interrupts into one vector, so even if we
+ * can try to request less vectors, we don't
+ * know how to associate interrupt events to
+ * vectors. Linux doesn't dupicate vectors
+ * in the MSIX table for this case.
+ */
+
+ printk(KERN_WARNING "bfad%d: "
+ "pci_enable_msix failed (%d),"
+ " use line based.\n", bfad->inst_no, error);
+
+ goto line_based;
+ }
+
+ /* Save the vectors */
+ for (i = 0; i < bfad->nvec; i++) {
+ bfa_trc(bfad, msix_entries[i].vector);
+ bfad->msix_tab[i].msix.vector = msix_entries[i].vector;
+ }
+
+ bfa_msix_init(&bfad->bfa, bfad->nvec);
+
+ bfad->bfad_flags |= BFAD_MSIX_ON;
+
+ return error;
+ }
+
+line_based:
+ error = 0;
+ if (request_irq
+ (bfad->pcidev->irq, (irq_handler_t) bfad_intx, BFAD_IRQ_FLAGS,
+ BFAD_DRIVER_NAME, bfad) != 0) {
+ /* Enable interrupt handler failed */
+ return 1;
+ }
+
+ return error;
+}
+
+void
+bfad_remove_intr(struct bfad_s *bfad)
+{
+ int i;
+
+ if (bfad->bfad_flags & BFAD_MSIX_ON) {
+ for (i = 0; i < bfad->nvec; i++)
+ free_irq(bfad->msix_tab[i].msix.vector,
+ &bfad->msix_tab[i]);
+
+ pci_disable_msix(bfad->pcidev);
+ bfad->bfad_flags &= ~BFAD_MSIX_ON;
+ } else {
+ free_irq(bfad->pcidev->irq, bfad);
+ }
+}
+
+
diff --git a/drivers/scsi/bfa/bfad_ipfc.h b/drivers/scsi/bfa/bfad_ipfc.h
new file mode 100644
index 000000000000..718bc5227671
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_ipfc.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DRV_IPFC_H__
+#define __BFA_DRV_IPFC_H__
+
+
+#define IPFC_NAME ""
+
+#define bfad_ipfc_module_init(x) do {} while (0)
+#define bfad_ipfc_module_exit(x) do {} while (0)
+#define bfad_ipfc_probe(x) do {} while (0)
+#define bfad_ipfc_probe_undo(x) do {} while (0)
+#define bfad_ipfc_port_config(x, y) BFA_STATUS_OK
+#define bfad_ipfc_port_unconfig(x, y) do {} while (0)
+
+#define bfad_ipfc_probe_post(x) do {} while (0)
+#define bfad_ipfc_port_new(x, y, z) BFA_STATUS_OK
+#define bfad_ipfc_port_delete(x, y) do {} while (0)
+#define bfad_ipfc_port_online(x, y) do {} while (0)
+#define bfad_ipfc_port_offline(x, y) do {} while (0)
+
+#define bfad_ip_get_attr(x) BFA_STATUS_FAILED
+#define bfad_ip_reset_drv_stats(x) BFA_STATUS_FAILED
+#define bfad_ip_get_drv_stats(x, y) BFA_STATUS_FAILED
+#define bfad_ip_enable_ipfc(x, y, z) BFA_STATUS_FAILED
+
+
+#endif
diff --git a/drivers/scsi/bfa/bfad_os.c b/drivers/scsi/bfa/bfad_os.c
new file mode 100644
index 000000000000..faf47b4f1a38
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_os.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfad_os.c Linux driver OS specific calls.
+ */
+
+#include "bfa_os_inc.h"
+#include "bfad_drv.h"
+
+void
+bfa_os_gettimeofday(struct bfa_timeval_s *tv)
+{
+ struct timeval tmp_tv;
+
+ do_gettimeofday(&tmp_tv);
+ tv->tv_sec = (u32) tmp_tv.tv_sec;
+ tv->tv_usec = (u32) tmp_tv.tv_usec;
+}
+
+void
+bfa_os_printf(struct bfa_log_mod_s *log_mod, u32 msg_id,
+ const char *fmt, ...)
+{
+ va_list ap;
+ #define BFA_STRING_256 256
+ char tmp[BFA_STRING_256];
+
+ va_start(ap, fmt);
+ vsprintf(tmp, fmt, ap);
+ va_end(ap);
+
+ printk(tmp);
+}
+
+
diff --git a/drivers/scsi/bfa/bfad_tm.h b/drivers/scsi/bfa/bfad_tm.h
new file mode 100644
index 000000000000..4901b1b7df02
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_tm.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/*
+ * Brocade Fibre Channel HBA Linux Target Mode Driver
+ */
+
+/**
+ * tm/dummy/bfad_tm.h BFA callback dummy header file for BFA Linux target mode PCI interface module.
+ */
+
+#ifndef __BFAD_TM_H__
+#define __BFAD_TM_H__
+
+#include <defs/bfa_defs_status.h>
+
+#define FCPT_NAME ""
+
+/*
+ * Called from base Linux driver on (De)Init events
+ */
+
+/* attach tgt template with scst */
+#define bfad_tm_module_init() do {} while (0)
+
+/* detach/release tgt template */
+#define bfad_tm_module_exit() do {} while (0)
+
+#define bfad_tm_probe(x) do {} while (0)
+#define bfad_tm_probe_undo(x) do {} while (0)
+#define bfad_tm_probe_post(x) do {} while (0)
+
+/*
+ * Called by base Linux driver but triggered by BFA FCS on config events
+ */
+#define bfad_tm_port_new(x, y) BFA_STATUS_OK
+#define bfad_tm_port_delete(x, y) do {} while (0)
+
+/*
+ * Called by base Linux driver but triggered by BFA FCS on PLOGI/O events
+ */
+#define bfad_tm_port_online(x, y) do {} while (0)
+#define bfad_tm_port_offline(x, y) do {} while (0)
+
+#endif
diff --git a/drivers/scsi/bfa/bfad_trcmod.h b/drivers/scsi/bfa/bfad_trcmod.h
new file mode 100644
index 000000000000..2827b2acd041
--- /dev/null
+++ b/drivers/scsi/bfa/bfad_trcmod.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfad_trcmod.h Linux driver trace modules
+ */
+
+
+#ifndef __BFAD_TRCMOD_H__
+#define __BFAD_TRCMOD_H__
+
+#include <cs/bfa_trc.h>
+
+/*
+ * !!! Only append to the enums defined here to avoid any versioning
+ * !!! needed between trace utility and driver version
+ */
+enum {
+ /* 2.6 Driver */
+ BFA_TRC_LDRV_BFAD = 1,
+ BFA_TRC_LDRV_BFAD_2_6 = 2,
+ BFA_TRC_LDRV_BFAD_2_6_9 = 3,
+ BFA_TRC_LDRV_BFAD_2_6_10 = 4,
+ BFA_TRC_LDRV_INTR = 5,
+ BFA_TRC_LDRV_IOCTL = 6,
+ BFA_TRC_LDRV_OS = 7,
+ BFA_TRC_LDRV_IM = 8,
+ BFA_TRC_LDRV_IM_2_6 = 9,
+ BFA_TRC_LDRV_IM_2_6_9 = 10,
+ BFA_TRC_LDRV_IM_2_6_10 = 11,
+ BFA_TRC_LDRV_TM = 12,
+ BFA_TRC_LDRV_IPFC = 13,
+ BFA_TRC_LDRV_IM_2_4 = 14,
+ BFA_TRC_LDRV_IM_VMW = 15,
+ BFA_TRC_LDRV_IM_LT_2_6_10 = 16,
+};
+
+#endif /* __BFAD_TRCMOD_H__ */
diff --git a/drivers/scsi/bfa/fab.c b/drivers/scsi/bfa/fab.c
new file mode 100644
index 000000000000..7e3a4d5d7bb4
--- /dev/null
+++ b/drivers/scsi/bfa/fab.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "lport_priv.h"
+
+/**
+ * fab.c port fab implementation.
+ */
+
+/**
+ * bfa_fcs_port_fab_public port fab public functions
+ */
+
+/**
+ * Called by port to initialize fabric services of the base port.
+ */
+void
+bfa_fcs_port_fab_init(struct bfa_fcs_port_s *port)
+{
+ bfa_fcs_port_ns_init(port);
+ bfa_fcs_port_scn_init(port);
+ bfa_fcs_port_ms_init(port);
+}
+
+/**
+ * Called by port to notify transition to online state.
+ */
+void
+bfa_fcs_port_fab_online(struct bfa_fcs_port_s *port)
+{
+ bfa_fcs_port_ns_online(port);
+ bfa_fcs_port_scn_online(port);
+}
+
+/**
+ * Called by port to notify transition to offline state.
+ */
+void
+bfa_fcs_port_fab_offline(struct bfa_fcs_port_s *port)
+{
+ bfa_fcs_port_ns_offline(port);
+ bfa_fcs_port_scn_offline(port);
+ bfa_fcs_port_ms_offline(port);
+}
diff --git a/drivers/scsi/bfa/fabric.c b/drivers/scsi/bfa/fabric.c
new file mode 100644
index 000000000000..a4b5dd449573
--- /dev/null
+++ b/drivers/scsi/bfa/fabric.c
@@ -0,0 +1,1278 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fabric.c Fabric module implementation.
+ */
+
+#include "fcs_fabric.h"
+#include "fcs_lport.h"
+#include "fcs_vport.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs_auth.h"
+#include "fcs.h"
+#include "fcbuild.h"
+#include <log/bfa_log_fcs.h>
+#include <aen/bfa_aen_port.h>
+#include <bfa_svc.h>
+
+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; \
+} while (0)
+
+/*
+ * forward declarations
+ */
+static void bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_delay(void *cbarg);
+static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_delete_comp(void *cbarg);
+static void bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric,
+ struct fchs_s *fchs, u16 len);
+static void bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric,
+ struct fchs_s *fchs, u16 len);
+static void bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric);
+static void bfa_fcs_fabric_flogiacc_comp(void *fcsarg,
+ struct bfa_fcxp_s *fcxp,
+ void *cbarg, bfa_status_t status,
+ u32 rsp_len,
+ u32 resid_len,
+ struct fchs_s *rspfchs);
+/**
+ * fcs_fabric_sm fabric state machine functions
+ */
+
+/**
+ * Fabric state machine events
+ */
+enum bfa_fcs_fabric_event {
+ BFA_FCS_FABRIC_SM_CREATE = 1, /* fabric create from driver */
+ BFA_FCS_FABRIC_SM_DELETE = 2, /* fabric delete from driver */
+ BFA_FCS_FABRIC_SM_LINK_DOWN = 3, /* link down from port */
+ BFA_FCS_FABRIC_SM_LINK_UP = 4, /* link up from port */
+ BFA_FCS_FABRIC_SM_CONT_OP = 5, /* continue op from flogi/auth */
+ BFA_FCS_FABRIC_SM_RETRY_OP = 6, /* continue op from flogi/auth */
+ BFA_FCS_FABRIC_SM_NO_FABRIC = 7, /* no fabric from flogi/auth
+ */
+ BFA_FCS_FABRIC_SM_PERF_EVFP = 8, /* perform EVFP from
+ *flogi/auth */
+ BFA_FCS_FABRIC_SM_ISOLATE = 9, /* isolate from EVFP processing */
+ BFA_FCS_FABRIC_SM_NO_TAGGING = 10,/* no VFT tagging from EVFP */
+ BFA_FCS_FABRIC_SM_DELAYED = 11, /* timeout delay event */
+ BFA_FCS_FABRIC_SM_AUTH_FAILED = 12, /* authentication failed */
+ BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13, /* authentication successful
+ */
+ BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */
+ BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */
+ BFA_FCS_FABRIC_SM_START = 16, /* fabric delete from driver */
+};
+
+static void bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+static void bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event);
+/**
+ * Beginning state before fabric creation.
+ */
+static void
+bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_CREATE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created);
+ bfa_fcs_fabric_init(fabric);
+ bfa_fcs_lport_init(&fabric->bport, fabric->fcs, FC_VF_ID_NULL,
+ &fabric->bport.port_cfg, NULL);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_UP:
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Beginning state before fabric creation.
+ */
+static void
+bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_START:
+ if (bfa_pport_is_linkup(fabric->fcs->bfa)) {
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
+ bfa_fcs_fabric_login(fabric);
+ } else
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_UP:
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
+ bfa_fcs_modexit_comp(fabric->fcs);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Link is down, awaiting LINK UP event from port. This is also the
+ * first state at fabric creation.
+ */
+static void
+bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_LINK_UP:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
+ bfa_fcs_fabric_login(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_RETRY_OP:
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * FLOGI is in progress, awaiting FLOGI reply.
+ */
+static void
+bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_CONT_OP:
+
+ bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
+ fabric->fab_type = BFA_FCS_FABRIC_SWITCHED;
+
+ if (fabric->auth_reqd && fabric->is_auth) {
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth);
+ bfa_trc(fabric->fcs, event);
+ } else {
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online);
+ bfa_fcs_fabric_notify_online(fabric);
+ }
+ break;
+
+ case BFA_FCS_FABRIC_SM_RETRY_OP:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi_retry);
+ bfa_timer_start(fabric->fcs->bfa, &fabric->delay_timer,
+ bfa_fcs_fabric_delay, fabric,
+ BFA_FCS_FABRIC_RETRY_DELAY);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LOOPBACK:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_loopback);
+ bfa_lps_discard(fabric->lps);
+ bfa_fcs_fabric_set_opertype(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_NO_FABRIC:
+ fabric->fab_type = BFA_FCS_FABRIC_N2N;
+ bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
+ bfa_fcs_fabric_notify_online(fabric);
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_nofabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_lps_discard(fabric->lps);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_lps_discard(fabric->lps);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+
+static void
+bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_DELAYED:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi);
+ bfa_fcs_fabric_login(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_timer_stop(&fabric->delay_timer);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_timer_stop(&fabric->delay_timer);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Authentication is in progress, awaiting authentication results.
+ */
+static void
+bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_AUTH_FAILED:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
+ bfa_lps_discard(fabric->lps);
+ break;
+
+ case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online);
+ bfa_fcs_fabric_notify_online(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_PERF_EVFP:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_lps_discard(fabric->lps);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Authentication failed
+ */
+static void
+bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_fcs_fabric_notify_offline(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Port is in loopback mode.
+ */
+static void
+bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_fcs_fabric_notify_offline(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * There is no attached fabric - private loop or NPort-to-NPort topology.
+ */
+static void
+bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_lps_discard(fabric->lps);
+ bfa_fcs_fabric_notify_offline(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_NO_FABRIC:
+ bfa_trc(fabric->fcs, fabric->bb_credit);
+ bfa_pport_set_tx_bbcredit(fabric->fcs->bfa, fabric->bb_credit);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Fabric is online - normal operating state.
+ */
+static void
+bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown);
+ bfa_lps_discard(fabric->lps);
+ bfa_fcs_fabric_notify_offline(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_DELETE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting);
+ bfa_fcs_fabric_delete(fabric);
+ break;
+
+ case BFA_FCS_FABRIC_SM_AUTH_FAILED:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed);
+ bfa_lps_discard(fabric->lps);
+ break;
+
+ case BFA_FCS_FABRIC_SM_AUTH_SUCCESS:
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * Exchanging virtual fabric parameters.
+ */
+static void
+bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_CONT_OP:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp_done);
+ break;
+
+ case BFA_FCS_FABRIC_SM_ISOLATE:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_isolated);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+/**
+ * EVFP exchange complete and VFT tagging is enabled.
+ */
+static void
+bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+}
+
+/**
+ * Port is isolated after EVFP exchange due to VF_ID mismatch (N and F).
+ */
+static void
+bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ bfa_log(fabric->fcs->logm, BFA_LOG_FCS_FABRIC_ISOLATED,
+ fabric->bport.port_cfg.pwwn, fabric->fcs->port_vfid,
+ fabric->event_arg.swp_vfid);
+}
+
+/**
+ * Fabric is being deleted, awaiting vport delete completions.
+ */
+static void
+bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric,
+ enum bfa_fcs_fabric_event event)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_FABRIC_SM_DELCOMP:
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
+ bfa_fcs_modexit_comp(fabric->fcs);
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_UP:
+ break;
+
+ case BFA_FCS_FABRIC_SM_LINK_DOWN:
+ bfa_fcs_fabric_notify_offline(fabric);
+ break;
+
+ default:
+ bfa_sm_fault(fabric->fcs, event);
+ }
+}
+
+
+
+/**
+ * fcs_fabric_private fabric private functions
+ */
+
+static void
+bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_port_cfg_s *port_cfg = &fabric->bport.port_cfg;
+
+ port_cfg->roles = BFA_PORT_ROLE_FCP_IM;
+ port_cfg->nwwn = bfa_ioc_get_nwwn(&fabric->fcs->bfa->ioc);
+ port_cfg->pwwn = bfa_ioc_get_pwwn(&fabric->fcs->bfa->ioc);
+}
+
+/**
+ * Port Symbolic Name Creation for base port.
+ */
+void
+bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_port_cfg_s *port_cfg = &fabric->bport.port_cfg;
+ struct bfa_adapter_attr_s adapter_attr;
+ struct bfa_fcs_driver_info_s *driver_info = &fabric->fcs->driver_info;
+
+ bfa_os_memset((void *)&adapter_attr, 0,
+ sizeof(struct bfa_adapter_attr_s));
+ bfa_ioc_get_adapter_attr(&fabric->fcs->bfa->ioc, &adapter_attr);
+
+ /*
+ * Model name/number
+ */
+ strncpy((char *)&port_cfg->sym_name, adapter_attr.model,
+ BFA_FCS_PORT_SYMBNAME_MODEL_SZ);
+ strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+ sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+
+ /*
+ * Driver Version
+ */
+ strncat((char *)&port_cfg->sym_name, (char *)driver_info->version,
+ BFA_FCS_PORT_SYMBNAME_VERSION_SZ);
+ strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+ sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+
+ /*
+ * Host machine name
+ */
+ strncat((char *)&port_cfg->sym_name,
+ (char *)driver_info->host_machine_name,
+ BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ);
+ strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+ sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+
+ /*
+ * Host OS Info :
+ * If OS Patch Info is not there, do not truncate any bytes from the
+ * OS name string and instead copy the entire OS info string (64 bytes).
+ */
+ if (driver_info->host_os_patch[0] == '\0') {
+ strncat((char *)&port_cfg->sym_name,
+ (char *)driver_info->host_os_name, BFA_FCS_OS_STR_LEN);
+ strncat((char *)&port_cfg->sym_name,
+ BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+ sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+ } else {
+ strncat((char *)&port_cfg->sym_name,
+ (char *)driver_info->host_os_name,
+ BFA_FCS_PORT_SYMBNAME_OSINFO_SZ);
+ strncat((char *)&port_cfg->sym_name,
+ BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+ sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+
+ /*
+ * Append host OS Patch Info
+ */
+ strncat((char *)&port_cfg->sym_name,
+ (char *)driver_info->host_os_patch,
+ BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ);
+ }
+
+ /*
+ * null terminate
+ */
+ port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0;
+}
+
+/**
+ * bfa lps login completion callback
+ */
+void
+bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status)
+{
+ struct bfa_fcs_fabric_s *fabric = uarg;
+
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_trc(fabric->fcs, status);
+
+ switch (status) {
+ case BFA_STATUS_OK:
+ fabric->stats.flogi_accepts++;
+ break;
+
+ case BFA_STATUS_INVALID_MAC:
+ /*
+ * Only for CNA
+ */
+ fabric->stats.flogi_acc_err++;
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
+
+ return;
+
+ case BFA_STATUS_EPROTOCOL:
+ switch (bfa_lps_get_extstatus(fabric->lps)) {
+ case BFA_EPROTO_BAD_ACCEPT:
+ fabric->stats.flogi_acc_err++;
+ break;
+
+ case BFA_EPROTO_UNKNOWN_RSP:
+ fabric->stats.flogi_unknown_rsp++;
+ break;
+
+ default:
+ break;
+ }
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
+
+ return;
+
+ case BFA_STATUS_FABRIC_RJT:
+ fabric->stats.flogi_rejects++;
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
+ return;
+
+ default:
+ fabric->stats.flogi_rsp_err++;
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP);
+ return;
+ }
+
+ fabric->bb_credit = bfa_lps_get_peer_bbcredit(fabric->lps);
+ bfa_trc(fabric->fcs, fabric->bb_credit);
+
+ if (!bfa_lps_is_brcd_fabric(fabric->lps))
+ fabric->fabric_name = bfa_lps_get_peer_nwwn(fabric->lps);
+
+ /*
+ * Check port type. It should be 1 = F-port.
+ */
+ if (bfa_lps_is_fport(fabric->lps)) {
+ fabric->bport.pid = bfa_lps_get_pid(fabric->lps);
+ fabric->is_npiv = bfa_lps_is_npiv_en(fabric->lps);
+ fabric->is_auth = bfa_lps_is_authreq(fabric->lps);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CONT_OP);
+ } else {
+ /*
+ * Nport-2-Nport direct attached
+ */
+ fabric->bport.port_topo.pn2n.rem_port_wwn =
+ bfa_lps_get_peer_pwwn(fabric->lps);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC);
+ }
+
+ bfa_trc(fabric->fcs, fabric->bport.pid);
+ bfa_trc(fabric->fcs, fabric->is_npiv);
+ bfa_trc(fabric->fcs, fabric->is_auth);
+}
+
+/**
+ * Allocate and send FLOGI.
+ */
+static void
+bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_s *bfa = fabric->fcs->bfa;
+ struct bfa_port_cfg_s *pcfg = &fabric->bport.port_cfg;
+ u8 alpa = 0;
+
+ if (bfa_pport_get_topology(bfa) == BFA_PPORT_TOPOLOGY_LOOP)
+ alpa = bfa_pport_get_myalpa(bfa);
+
+ bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_pport_get_maxfrsize(bfa),
+ pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd);
+
+ fabric->stats.flogi_sent++;
+}
+
+static void
+bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_fcs_vport_s *vport;
+ struct list_head *qe, *qen;
+
+ bfa_trc(fabric->fcs, fabric->fabric_name);
+
+ bfa_fcs_fabric_set_opertype(fabric);
+ fabric->stats.fabric_onlines++;
+
+ /**
+ * notify online event to base and then virtual ports
+ */
+ bfa_fcs_port_online(&fabric->bport);
+
+ list_for_each_safe(qe, qen, &fabric->vport_q) {
+ vport = (struct bfa_fcs_vport_s *)qe;
+ bfa_fcs_vport_online(vport);
+ }
+}
+
+static void
+bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_fcs_vport_s *vport;
+ struct list_head *qe, *qen;
+
+ bfa_trc(fabric->fcs, fabric->fabric_name);
+ fabric->stats.fabric_offlines++;
+
+ /**
+ * notify offline event first to vports and then base port.
+ */
+ list_for_each_safe(qe, qen, &fabric->vport_q) {
+ vport = (struct bfa_fcs_vport_s *)qe;
+ bfa_fcs_vport_offline(vport);
+ }
+
+ bfa_fcs_port_offline(&fabric->bport);
+
+ fabric->fabric_name = 0;
+ fabric->fabric_ip_addr[0] = 0;
+}
+
+static void
+bfa_fcs_fabric_delay(void *cbarg)
+{
+ struct bfa_fcs_fabric_s *fabric = cbarg;
+
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED);
+}
+
+/**
+ * Delete all vports and wait for vport delete completions.
+ */
+static void
+bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_fcs_vport_s *vport;
+ struct list_head *qe, *qen;
+
+ list_for_each_safe(qe, qen, &fabric->vport_q) {
+ vport = (struct bfa_fcs_vport_s *)qe;
+ bfa_fcs_vport_delete(vport);
+ }
+
+ bfa_fcs_port_delete(&fabric->bport);
+ bfa_wc_wait(&fabric->wc);
+}
+
+static void
+bfa_fcs_fabric_delete_comp(void *cbarg)
+{
+ struct bfa_fcs_fabric_s *fabric = cbarg;
+
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP);
+}
+
+
+
+/**
+ * fcs_fabric_public fabric public functions
+ */
+
+/**
+ * Module initialization
+ */
+void
+bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs)
+{
+ struct bfa_fcs_fabric_s *fabric;
+
+ fabric = &fcs->fabric;
+ bfa_os_memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s));
+
+ /**
+ * Initialize base fabric.
+ */
+ fabric->fcs = fcs;
+ INIT_LIST_HEAD(&fabric->vport_q);
+ INIT_LIST_HEAD(&fabric->vf_q);
+ fabric->lps = bfa_lps_alloc(fcs->bfa);
+ bfa_assert(fabric->lps);
+
+ /**
+ * Initialize fabric delete completion handler. Fabric deletion is complete
+ * when the last vport delete is complete.
+ */
+ bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric);
+ bfa_wc_up(&fabric->wc); /* For the base port */
+
+ bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CREATE);
+ bfa_trc(fcs, 0);
+}
+
+/**
+ * Module cleanup
+ */
+void
+bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs)
+{
+ struct bfa_fcs_fabric_s *fabric;
+
+ bfa_trc(fcs, 0);
+
+ /**
+ * Cleanup base fabric.
+ */
+ fabric = &fcs->fabric;
+ bfa_lps_delete(fabric->lps);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE);
+}
+
+/**
+ * Fabric module start -- kick starts FCS actions
+ */
+void
+bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs)
+{
+ struct bfa_fcs_fabric_s *fabric;
+
+ bfa_trc(fcs, 0);
+ fabric = &fcs->fabric;
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_START);
+}
+
+/**
+ * Suspend fabric activity as part of driver suspend.
+ */
+void
+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);
+}
+
+enum bfa_pport_type
+bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric)
+{
+ return fabric->oper_type;
+}
+
+/**
+ * Link up notification from BFA physical port module.
+ */
+void
+bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_UP);
+}
+
+/**
+ * Link down notification from BFA physical port module.
+ */
+void
+bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric)
+{
+ bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN);
+}
+
+/**
+ * A child vport is being created in the fabric.
+ *
+ * Call from vport module at vport creation. A list of base port and vports
+ * belonging to a fabric is maintained to propagate link events.
+ *
+ * param[in] fabric - Fabric instance. This can be a base fabric or vf.
+ * param[in] vport - Vport being created.
+ *
+ * @return None (always succeeds)
+ */
+void
+bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
+ struct bfa_fcs_vport_s *vport)
+{
+ /**
+ * - add vport to fabric's vport_q
+ */
+ bfa_trc(fabric->fcs, fabric->vf_id);
+
+ list_add_tail(&vport->qe, &fabric->vport_q);
+ fabric->num_vports++;
+ bfa_wc_up(&fabric->wc);
+}
+
+/**
+ * A child vport is being deleted from fabric.
+ *
+ * Vport is being deleted.
+ */
+void
+bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric,
+ struct bfa_fcs_vport_s *vport)
+{
+ list_del(&vport->qe);
+ fabric->num_vports--;
+ bfa_wc_down(&fabric->wc);
+}
+
+/**
+ * Base port is deleted.
+ */
+void
+bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric)
+{
+ bfa_wc_down(&fabric->wc);
+}
+
+/**
+ * Check if fabric is online.
+ *
+ * param[in] fabric - Fabric instance. This can be a base fabric or vf.
+ *
+ * @return TRUE/FALSE
+ */
+int
+bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric)
+{
+ return bfa_sm_cmp_state(fabric, bfa_fcs_fabric_sm_online);
+}
+
+
+bfa_status_t
+bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf, struct bfa_fcs_s *fcs,
+ struct bfa_port_cfg_s *port_cfg,
+ struct bfad_vf_s *vf_drv)
+{
+ bfa_sm_set_state(vf, bfa_fcs_fabric_sm_uninit);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Lookup for a vport withing a fabric given its pwwn
+ */
+struct bfa_fcs_vport_s *
+bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn)
+{
+ struct bfa_fcs_vport_s *vport;
+ struct list_head *qe;
+
+ list_for_each(qe, &fabric->vport_q) {
+ vport = (struct bfa_fcs_vport_s *)qe;
+ if (bfa_fcs_port_get_pwwn(&vport->lport) == pwwn)
+ return vport;
+ }
+
+ return NULL;
+}
+
+/**
+ * In a given fabric, return the number of lports.
+ *
+ * param[in] fabric - Fabric instance. This can be a base fabric or vf.
+ *
+* @return : 1 or more.
+ */
+u16
+bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric)
+{
+ return fabric->num_vports;
+}
+
+/**
+ * Unsolicited frame receive handling.
+ */
+void
+bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
+ u16 len)
+{
+ u32 pid = fchs->d_id;
+ struct bfa_fcs_vport_s *vport;
+ struct list_head *qe;
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+ struct fc_logi_s *flogi = (struct fc_logi_s *) els_cmd;
+
+ bfa_trc(fabric->fcs, len);
+ bfa_trc(fabric->fcs, pid);
+
+ /**
+ * Look for our own FLOGI frames being looped back. This means an
+ * external loopback cable is in place. Our own FLOGI frames are
+ * sometimes looped back when switch port gets temporarily bypassed.
+ */
+ if ((pid == bfa_os_ntoh3b(FC_FABRIC_PORT))
+ && (els_cmd->els_code == FC_ELS_FLOGI)
+ && (flogi->port_name == bfa_fcs_port_get_pwwn(&fabric->bport))) {
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LOOPBACK);
+ return;
+ }
+
+ /**
+ * FLOGI/EVFP exchanges should be consumed by base fabric.
+ */
+ if (fchs->d_id == bfa_os_hton3b(FC_FABRIC_PORT)) {
+ bfa_trc(fabric->fcs, pid);
+ bfa_fcs_fabric_process_uf(fabric, fchs, len);
+ return;
+ }
+
+ if (fabric->bport.pid == pid) {
+ /**
+ * All authentication frames should be routed to auth
+ */
+ bfa_trc(fabric->fcs, els_cmd->els_code);
+ if (els_cmd->els_code == FC_ELS_AUTH) {
+ bfa_trc(fabric->fcs, els_cmd->els_code);
+ fabric->auth.response = (u8 *) els_cmd;
+ return;
+ }
+
+ bfa_trc(fabric->fcs, *(u8 *) ((u8 *) fchs));
+ bfa_fcs_port_uf_recv(&fabric->bport, fchs, len);
+ return;
+ }
+
+ /**
+ * look for a matching local port ID
+ */
+ list_for_each(qe, &fabric->vport_q) {
+ vport = (struct bfa_fcs_vport_s *)qe;
+ if (vport->lport.pid == pid) {
+ bfa_fcs_port_uf_recv(&vport->lport, fchs, len);
+ return;
+ }
+ }
+ bfa_trc(fabric->fcs, els_cmd->els_code);
+ bfa_fcs_port_uf_recv(&fabric->bport, fchs, len);
+}
+
+/**
+ * Unsolicited frames to be processed by fabric.
+ */
+static void
+bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs,
+ u16 len)
+{
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+
+ bfa_trc(fabric->fcs, els_cmd->els_code);
+
+ switch (els_cmd->els_code) {
+ case FC_ELS_FLOGI:
+ bfa_fcs_fabric_process_flogi(fabric, fchs, len);
+ break;
+
+ default:
+ /*
+ * need to generate a LS_RJT
+ */
+ break;
+ }
+}
+
+/**
+ * Process incoming FLOGI
+ */
+static void
+bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric,
+ struct fchs_s *fchs, u16 len)
+{
+ struct fc_logi_s *flogi = (struct fc_logi_s *) (fchs + 1);
+ struct bfa_fcs_port_s *bport = &fabric->bport;
+
+ bfa_trc(fabric->fcs, fchs->s_id);
+
+ fabric->stats.flogi_rcvd++;
+ /*
+ * Check port type. It should be 0 = n-port.
+ */
+ if (flogi->csp.port_type) {
+ /*
+ * @todo: may need to send a LS_RJT
+ */
+ bfa_trc(fabric->fcs, flogi->port_name);
+ fabric->stats.flogi_rejected++;
+ return;
+ }
+
+ fabric->bb_credit = bfa_os_ntohs(flogi->csp.bbcred);
+ bport->port_topo.pn2n.rem_port_wwn = flogi->port_name;
+ bport->port_topo.pn2n.reply_oxid = fchs->ox_id;
+
+ /*
+ * Send a Flogi Acc
+ */
+ bfa_fcs_fabric_send_flogi_acc(fabric);
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC);
+}
+
+static void
+bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric)
+{
+ struct bfa_port_cfg_s *pcfg = &fabric->bport.port_cfg;
+ struct bfa_fcs_port_n2n_s *n2n_port = &fabric->bport.port_topo.pn2n;
+ struct bfa_s *bfa = fabric->fcs->bfa;
+ struct bfa_fcxp_s *fcxp;
+ u16 reqlen;
+ struct fchs_s fchs;
+
+ fcxp = bfa_fcs_fcxp_alloc(fabric->fcs);
+ /**
+ * Do not expect this failure -- expect remote node to retry
+ */
+ if (!fcxp)
+ return;
+
+ reqlen = fc_flogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_os_hton3b(FC_FABRIC_PORT),
+ n2n_port->reply_oxid, pcfg->pwwn,
+ pcfg->nwwn, bfa_pport_get_maxfrsize(bfa),
+ bfa_pport_get_rx_bbcredit(bfa));
+
+ bfa_fcxp_send(fcxp, NULL, fabric->vf_id, bfa_lps_get_tag(fabric->lps),
+ BFA_FALSE, FC_CLASS_3, reqlen, &fchs,
+ bfa_fcs_fabric_flogiacc_comp, fabric,
+ FC_MAX_PDUSZ, 0); /* Timeout 0 indicates no
+ * response expected
+ */
+}
+
+/**
+ * Flogi Acc completion callback.
+ */
+static void
+bfa_fcs_fabric_flogiacc_comp(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg,
+ bfa_status_t status, u32 rsp_len,
+ u32 resid_len, struct fchs_s *rspfchs)
+{
+ struct bfa_fcs_fabric_s *fabric = cbarg;
+
+ bfa_trc(fabric->fcs, status);
+}
+
+/*
+ *
+ * @param[in] fabric - fabric
+ * @param[in] result - 1
+ *
+ * @return - none
+ */
+void
+bfa_fcs_auth_finished(struct bfa_fcs_fabric_s *fabric, enum auth_status status)
+{
+ bfa_trc(fabric->fcs, status);
+
+ if (status == FC_AUTH_STATE_SUCCESS)
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_AUTH_SUCCESS);
+ else
+ bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_AUTH_FAILED);
+}
+
+/**
+ * Send AEN notification
+ */
+static void
+bfa_fcs_fabric_aen_post(struct bfa_fcs_port_s *port,
+ enum bfa_port_aen_event event)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = port->fcs->logm;
+ wwn_t pwwn = bfa_fcs_port_get_pwwn(port);
+ wwn_t fwwn = bfa_fcs_port_get_fabric_name(port);
+ char pwwn_ptr[BFA_STRING_32];
+ char fwwn_ptr[BFA_STRING_32];
+
+ wwn2str(pwwn_ptr, pwwn);
+ wwn2str(fwwn_ptr, fwwn);
+
+ switch (event) {
+ case BFA_PORT_AEN_FABRIC_NAME_CHANGE:
+ bfa_log(logmod, BFA_AEN_PORT_FABRIC_NAME_CHANGE, pwwn_ptr,
+ fwwn_ptr);
+ break;
+ default:
+ break;
+ }
+
+ aen_data.port.pwwn = pwwn;
+ aen_data.port.fwwn = fwwn;
+}
+
+/*
+ *
+ * @param[in] fabric - fabric
+ * @param[in] wwn_t - new fabric name
+ *
+ * @return - none
+ */
+void
+bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
+ wwn_t fabric_name)
+{
+ bfa_trc(fabric->fcs, fabric_name);
+
+ if (fabric->fabric_name == 0) {
+ /*
+ * With BRCD switches, we don't get Fabric Name in FLOGI.
+ * Don't generate a fabric name change event in this case.
+ */
+ fabric->fabric_name = fabric_name;
+ } else {
+ fabric->fabric_name = fabric_name;
+ /*
+ * Generate a Event
+ */
+ bfa_fcs_fabric_aen_post(&fabric->bport,
+ BFA_PORT_AEN_FABRIC_NAME_CHANGE);
+ }
+
+}
+
+/**
+ * Not used by FCS.
+ */
+void
+bfa_cb_lps_flogo_comp(void *bfad, void *uarg)
+{
+}
+
+
diff --git a/drivers/scsi/bfa/fcbuild.c b/drivers/scsi/bfa/fcbuild.c
new file mode 100644
index 000000000000..fee5456451cb
--- /dev/null
+++ b/drivers/scsi/bfa/fcbuild.c
@@ -0,0 +1,1449 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * fcbuild.c - FC link service frame building and parsing routines
+ */
+
+#include <bfa_os_inc.h>
+#include "fcbuild.h"
+
+/*
+ * static build functions
+ */
+static void fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id);
+static void fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id);
+static struct fchs_s fc_els_req_tmpl;
+static struct fchs_s fc_els_rsp_tmpl;
+static struct fchs_s fc_bls_req_tmpl;
+static struct fchs_s fc_bls_rsp_tmpl;
+static struct fc_ba_acc_s ba_acc_tmpl;
+static struct fc_logi_s plogi_tmpl;
+static struct fc_prli_s prli_tmpl;
+static struct fc_rrq_s rrq_tmpl;
+static struct fchs_s fcp_fchs_tmpl;
+
+void
+fcbuild_init(void)
+{
+ /*
+ * fc_els_req_tmpl
+ */
+ fc_els_req_tmpl.routing = FC_RTG_EXT_LINK;
+ fc_els_req_tmpl.cat_info = FC_CAT_LD_REQUEST;
+ fc_els_req_tmpl.type = FC_TYPE_ELS;
+ fc_els_req_tmpl.f_ctl =
+ bfa_os_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
+ FCTL_SI_XFER);
+ fc_els_req_tmpl.rx_id = FC_RXID_ANY;
+
+ /*
+ * fc_els_rsp_tmpl
+ */
+ fc_els_rsp_tmpl.routing = FC_RTG_EXT_LINK;
+ fc_els_rsp_tmpl.cat_info = FC_CAT_LD_REPLY;
+ fc_els_rsp_tmpl.type = FC_TYPE_ELS;
+ fc_els_rsp_tmpl.f_ctl =
+ bfa_os_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
+ FCTL_END_SEQ | FCTL_SI_XFER);
+ fc_els_rsp_tmpl.rx_id = FC_RXID_ANY;
+
+ /*
+ * fc_bls_req_tmpl
+ */
+ fc_bls_req_tmpl.routing = FC_RTG_BASIC_LINK;
+ fc_bls_req_tmpl.type = FC_TYPE_BLS;
+ fc_bls_req_tmpl.f_ctl = bfa_os_hton3b(FCTL_END_SEQ | FCTL_SI_XFER);
+ fc_bls_req_tmpl.rx_id = FC_RXID_ANY;
+
+ /*
+ * fc_bls_rsp_tmpl
+ */
+ fc_bls_rsp_tmpl.routing = FC_RTG_BASIC_LINK;
+ fc_bls_rsp_tmpl.cat_info = FC_CAT_BA_ACC;
+ fc_bls_rsp_tmpl.type = FC_TYPE_BLS;
+ fc_bls_rsp_tmpl.f_ctl =
+ bfa_os_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH |
+ FCTL_END_SEQ | FCTL_SI_XFER);
+ fc_bls_rsp_tmpl.rx_id = FC_RXID_ANY;
+
+ /*
+ * ba_acc_tmpl
+ */
+ ba_acc_tmpl.seq_id_valid = 0;
+ ba_acc_tmpl.low_seq_cnt = 0;
+ ba_acc_tmpl.high_seq_cnt = 0xFFFF;
+
+ /*
+ * plogi_tmpl
+ */
+ plogi_tmpl.csp.verhi = FC_PH_VER_PH_3;
+ plogi_tmpl.csp.verlo = FC_PH_VER_4_3;
+ plogi_tmpl.csp.bbcred = bfa_os_htons(0x0004);
+ plogi_tmpl.csp.ciro = 0x1;
+ plogi_tmpl.csp.cisc = 0x0;
+ plogi_tmpl.csp.altbbcred = 0x0;
+ plogi_tmpl.csp.conseq = bfa_os_htons(0x00FF);
+ plogi_tmpl.csp.ro_bitmap = bfa_os_htons(0x0002);
+ plogi_tmpl.csp.e_d_tov = bfa_os_htonl(2000);
+
+ plogi_tmpl.class3.class_valid = 1;
+ plogi_tmpl.class3.sequential = 1;
+ plogi_tmpl.class3.conseq = 0xFF;
+ plogi_tmpl.class3.ospx = 1;
+
+ /*
+ * prli_tmpl
+ */
+ prli_tmpl.command = FC_ELS_PRLI;
+ prli_tmpl.pglen = 0x10;
+ prli_tmpl.pagebytes = bfa_os_htons(0x0014);
+ prli_tmpl.parampage.type = FC_TYPE_FCP;
+ prli_tmpl.parampage.imagepair = 1;
+ prli_tmpl.parampage.servparams.rxrdisab = 1;
+
+ /*
+ * rrq_tmpl
+ */
+ rrq_tmpl.els_cmd.els_code = FC_ELS_RRQ;
+
+ /*
+ * fcp_fchs_tmpl
+ */
+ fcp_fchs_tmpl.routing = FC_RTG_FC4_DEV_DATA;
+ fcp_fchs_tmpl.cat_info = FC_CAT_UNSOLICIT_CMD;
+ fcp_fchs_tmpl.type = FC_TYPE_FCP;
+ fcp_fchs_tmpl.f_ctl =
+ bfa_os_hton3b(FCTL_FS_EXCH | FCTL_END_SEQ | FCTL_SI_XFER);
+ fcp_fchs_tmpl.seq_id = 1;
+ fcp_fchs_tmpl.rx_id = FC_RXID_ANY;
+}
+
+static void
+fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u32 ox_id)
+{
+ bfa_os_memset(fchs, 0, sizeof(struct fchs_s));
+
+ fchs->routing = FC_RTG_FC4_DEV_DATA;
+ fchs->cat_info = FC_CAT_UNSOLICIT_CTRL;
+ fchs->type = FC_TYPE_SERVICES;
+ fchs->f_ctl =
+ bfa_os_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ |
+ FCTL_SI_XFER);
+ fchs->rx_id = FC_RXID_ANY;
+ fchs->d_id = (d_id);
+ fchs->s_id = (s_id);
+ fchs->ox_id = bfa_os_htons(ox_id);
+
+ /**
+ * @todo no need to set ox_id for request
+ * no need to set rx_id for response
+ */
+}
+
+void
+fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id)
+{
+ bfa_os_memcpy(fchs, &fc_els_req_tmpl, sizeof(struct fchs_s));
+ fchs->d_id = (d_id);
+ fchs->s_id = (s_id);
+ fchs->ox_id = bfa_os_htons(ox_id);
+}
+
+static void
+fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id)
+{
+ bfa_os_memcpy(fchs, &fc_els_rsp_tmpl, sizeof(struct fchs_s));
+ fchs->d_id = d_id;
+ fchs->s_id = s_id;
+ fchs->ox_id = ox_id;
+}
+
+enum fc_parse_status
+fc_els_rsp_parse(struct fchs_s *fchs, int len)
+{
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+ struct fc_ls_rjt_s *ls_rjt = (struct fc_ls_rjt_s *) els_cmd;
+
+ len = 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;
+ else
+ return FC_PARSE_FAILURE;
+
+ case FC_ELS_ACC:
+ return FC_PARSE_OK;
+ }
+ return FC_PARSE_OK;
+}
+
+static void
+fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id)
+{
+ bfa_os_memcpy(fchs, &fc_bls_rsp_tmpl, sizeof(struct fchs_s));
+ fchs->d_id = d_id;
+ fchs->s_id = s_id;
+ fchs->ox_id = ox_id;
+}
+
+static u16
+fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size, u8 els_code)
+{
+ struct fc_logi_s *plogi = (struct fc_logi_s *) (pld);
+
+ bfa_os_memcpy(plogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+
+ plogi->els_cmd.els_code = els_code;
+ if (els_code == FC_ELS_PLOGI)
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ else
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ plogi->csp.rxsz = plogi->class3.rxsz = bfa_os_htons(pdu_size);
+
+ 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);
+}
+
+u16
+fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size, u8 set_npiv, u8 set_auth,
+ u16 local_bb_credits)
+{
+ u32 d_id = bfa_os_hton3b(FC_FABRIC_PORT);
+ u32 *vvl_info;
+
+ bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+
+ flogi->els_cmd.els_code = FC_ELS_FLOGI;
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+ flogi->port_name = port_name;
+ flogi->node_name = node_name;
+
+ /*
+ * Set the NPIV Capability Bit ( word 1, bit 31) of Common
+ * Service Parameters.
+ */
+ flogi->csp.ciro = set_npiv;
+
+ /* set AUTH capability */
+ flogi->csp.security = set_auth;
+
+ flogi->csp.bbcred = bfa_os_htons(local_bb_credits);
+
+ /* Set brcd token in VVL */
+ vvl_info = (u32 *)&flogi->vvl[0];
+
+ /* set the flag to indicate the presence of VVL */
+ 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);
+}
+
+u16
+fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size, u16 local_bb_credits)
+{
+ u32 d_id = 0;
+
+ bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ flogi->els_cmd.els_code = FC_ELS_ACC;
+ flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+ flogi->port_name = port_name;
+ flogi->node_name = node_name;
+
+ flogi->csp.bbcred = bfa_os_htons(local_bb_credits);
+
+ return sizeof(struct fc_logi_s);
+}
+
+u16
+fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size)
+{
+ u32 d_id = bfa_os_hton3b(FC_FABRIC_PORT);
+
+ bfa_os_memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s));
+
+ flogi->els_cmd.els_code = FC_ELS_FDISC;
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ flogi->csp.rxsz = flogi->class3.rxsz = bfa_os_htons(pdu_size);
+ flogi->port_name = port_name;
+ flogi->node_name = node_name;
+
+ return sizeof(struct fc_logi_s);
+}
+
+u16
+fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size)
+{
+ return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name,
+ node_name, pdu_size, FC_ELS_PLOGI);
+}
+
+u16
+fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size)
+{
+ return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name,
+ node_name, pdu_size, FC_ELS_ACC);
+}
+
+enum fc_parse_status
+fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name)
+{
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+ struct fc_logi_s *plogi;
+ struct fc_ls_rjt_s *ls_rjt;
+
+ switch (els_cmd->els_code) {
+ 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;
+ else
+ 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;
+
+ if (!wwn_is_equal(plogi->port_name, port_name))
+ return FC_PARSE_FAILURE;
+
+ if (!plogi->class3.class_valid)
+ return FC_PARSE_FAILURE;
+
+ if (bfa_os_ntohs(plogi->class3.rxsz) < (FC_MIN_PDUSZ))
+ return FC_PARSE_FAILURE;
+
+ return FC_PARSE_OK;
+ default:
+ return FC_PARSE_FAILURE;
+ }
+}
+
+enum fc_parse_status
+fc_plogi_parse(struct fchs_s *fchs)
+{
+ struct fc_logi_s *plogi = (struct fc_logi_s *) (fchs + 1);
+
+ if (plogi->class3.class_valid != 1)
+ return FC_PARSE_FAILURE;
+
+ 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_OK;
+}
+
+u16
+fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id)
+{
+ struct fc_prli_s *prli = (struct fc_prli_s *) (pld);
+
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
+
+ prli->command = FC_ELS_PRLI;
+ prli->parampage.servparams.initiator = 1;
+ prli->parampage.servparams.retry = 1;
+ prli->parampage.servparams.rec_support = 1;
+ prli->parampage.servparams.task_retry_id = 0;
+ prli->parampage.servparams.confirm = 1;
+
+ return sizeof(struct fc_prli_s);
+}
+
+u16
+fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id, enum bfa_port_role role)
+{
+ struct fc_prli_s *prli = (struct fc_prli_s *) (pld);
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+ bfa_os_memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s));
+
+ prli->command = FC_ELS_ACC;
+
+ if ((role & BFA_PORT_ROLE_FCP_TM) == BFA_PORT_ROLE_FCP_TM)
+ prli->parampage.servparams.target = 1;
+ else
+ prli->parampage.servparams.initiator = 1;
+
+ prli->parampage.rspcode = FC_PRLI_ACC_XQTD;
+
+ 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;
+
+ if (prli->command != FC_ELS_ACC)
+ return FC_PARSE_FAILURE;
+
+ if ((prli->parampage.rspcode != FC_PRLI_ACC_XQTD)
+ && (prli->parampage.rspcode != FC_PRLI_ACC_PREDEF_IMG))
+ return FC_PARSE_FAILURE;
+
+ if (prli->parampage.servparams.target != 1)
+ return FC_PARSE_FAILURE;
+
+ 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;
+
+ if (!prli->parampage.imagepair)
+ return FC_PARSE_FAILURE;
+
+ if (!prli->parampage.servparams.initiator)
+ return FC_PARSE_FAILURE;
+
+ return FC_PARSE_OK;
+}
+
+u16
+fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id,
+ u32 s_id, u16 ox_id, wwn_t port_name)
+{
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ memset(logo, '\0', sizeof(struct fc_logo_s));
+ logo->els_cmd.els_code = FC_ELS_LOGO;
+ logo->nport_id = (s_id);
+ logo->orig_port_name = port_name;
+
+ return sizeof(struct fc_logo_s);
+}
+
+static u16
+fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name, u8 els_code)
+{
+ memset(adisc, '\0', sizeof(struct fc_adisc_s));
+
+ adisc->els_cmd.els_code = els_code;
+
+ if (els_code == FC_ELS_ADISC)
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ else
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ adisc->orig_HA = 0;
+ adisc->orig_port_name = port_name;
+ adisc->orig_node_name = node_name;
+ adisc->nport_id = (s_id);
+
+ return sizeof(struct fc_adisc_s);
+}
+
+u16
+fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name)
+{
+ return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name,
+ node_name, FC_ELS_ADISC);
+}
+
+u16
+fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name)
+{
+ return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name,
+ node_name, FC_ELS_ACC);
+}
+
+enum fc_parse_status
+fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, wwn_t port_name,
+ wwn_t node_name)
+{
+
+ if (len < sizeof(struct fc_adisc_s))
+ return FC_PARSE_FAILURE;
+
+ if (adisc->els_cmd.els_code != FC_ELS_ACC)
+ return FC_PARSE_FAILURE;
+
+ if (!wwn_is_equal(adisc->orig_port_name, port_name))
+ return FC_PARSE_FAILURE;
+
+ return FC_PARSE_OK;
+}
+
+enum fc_parse_status
+fc_adisc_parse(struct fchs_s *fchs, void *pld, u32 host_dap,
+ wwn_t node_name, wwn_t port_name)
+{
+ struct fc_adisc_s *adisc = (struct fc_adisc_s *) pld;
+
+ if (adisc->els_cmd.els_code != FC_ELS_ACC)
+ 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_FAILURE;
+}
+
+enum fc_parse_status
+fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name)
+{
+ struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1);
+
+ if (pdisc->class3.class_valid != 1)
+ return FC_PARSE_FAILURE;
+
+ if ((bfa_os_ntohs(pdisc->class3.rxsz) <
+ (FC_MIN_PDUSZ - sizeof(struct fchs_s)))
+ || (pdisc->class3.rxsz == 0))
+ return FC_PARSE_FAILURE;
+
+ if (!wwn_is_equal(pdisc->port_name, port_name))
+ return FC_PARSE_FAILURE;
+
+ if (!wwn_is_equal(pdisc->node_name, node_name))
+ return FC_PARSE_FAILURE;
+
+ return FC_PARSE_OK;
+}
+
+u16
+fc_abts_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id)
+{
+ bfa_os_memcpy(fchs, &fc_bls_req_tmpl, sizeof(struct fchs_s));
+ fchs->cat_info = FC_CAT_ABTS;
+ fchs->d_id = (d_id);
+ fchs->s_id = (s_id);
+ fchs->ox_id = bfa_os_htons(ox_id);
+
+ return sizeof(struct fchs_s);
+}
+
+enum fc_parse_status
+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_FAILURE;
+}
+
+u16
+fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id,
+ u32 s_id, u16 ox_id, u16 rrq_oxid)
+{
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ /*
+ * build rrq payload
+ */
+ bfa_os_memcpy(rrq, &rrq_tmpl, sizeof(struct fc_rrq_s));
+ rrq->s_id = (s_id);
+ rrq->ox_id = bfa_os_htons(rrq_oxid);
+ rrq->rx_id = FC_RXID_ANY;
+
+ return sizeof(struct fc_rrq_s);
+}
+
+u16
+fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id,
+ u16 ox_id)
+{
+ struct fc_els_cmd_s *acc = pld;
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ memset(acc, 0, sizeof(struct fc_els_cmd_s));
+ acc->els_code = FC_ELS_ACC;
+
+ return sizeof(struct fc_els_cmd_s);
+}
+
+u16
+fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, u32 d_id,
+ u32 s_id, u16 ox_id, u8 reason_code,
+ u8 reason_code_expl)
+{
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+ memset(ls_rjt, 0, sizeof(struct fc_ls_rjt_s));
+
+ ls_rjt->els_cmd.els_code = FC_ELS_LS_RJT;
+ ls_rjt->reason_code = reason_code;
+ ls_rjt->reason_code_expl = reason_code_expl;
+ ls_rjt->vendor_unique = 0x00;
+
+ return sizeof(struct fc_ls_rjt_s);
+}
+
+u16
+fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id,
+ u32 s_id, u16 ox_id, u16 rx_id)
+{
+ fc_bls_rsp_build(fchs, d_id, s_id, ox_id);
+
+ bfa_os_memcpy(ba_acc, &ba_acc_tmpl, sizeof(struct fc_ba_acc_s));
+
+ fchs->rx_id = rx_id;
+
+ ba_acc->ox_id = fchs->ox_id;
+ ba_acc->rx_id = fchs->rx_id;
+
+ return sizeof(struct fc_ba_acc_s);
+}
+
+u16
+fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd,
+ u32 d_id, u32 s_id, u16 ox_id)
+{
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+ memset(els_cmd, 0, sizeof(struct fc_els_cmd_s));
+ els_cmd->els_code = FC_ELS_ACC;
+
+ return sizeof(struct fc_els_cmd_s);
+}
+
+int
+fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code)
+{
+ int num_pages = 0;
+ struct fc_prlo_s *prlo;
+ struct fc_tprlo_s *tprlo;
+
+ if (els_code == FC_ELS_PRLO) {
+ prlo = (struct fc_prlo_s *) (fc_frame + 1);
+ num_pages = (bfa_os_ntohs(prlo->payload_len) - 4) / 16;
+ } else {
+ tprlo = (struct fc_tprlo_s *) (fc_frame + 1);
+ num_pages = (bfa_os_ntohs(tprlo->payload_len) - 4) / 16;
+ }
+ return num_pages;
+}
+
+u16
+fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ int num_pages)
+{
+ int page;
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ memset(tprlo_acc, 0, (num_pages * 16) + 4);
+ tprlo_acc->command = FC_ELS_ACC;
+
+ tprlo_acc->page_len = 0x10;
+ tprlo_acc->payload_len = bfa_os_htons((num_pages * 16) + 4);
+
+ for (page = 0; page < num_pages; page++) {
+ tprlo_acc->tprlo_acc_params[page].opa_valid = 0;
+ tprlo_acc->tprlo_acc_params[page].rpa_valid = 0;
+ tprlo_acc->tprlo_acc_params[page].fc4type_csp = FC_TYPE_FCP;
+ 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);
+}
+
+u16
+fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ int num_pages)
+{
+ int page;
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ memset(prlo_acc, 0, (num_pages * 16) + 4);
+ prlo_acc->command = FC_ELS_ACC;
+ prlo_acc->page_len = 0x10;
+ prlo_acc->payload_len = bfa_os_htons((num_pages * 16) + 4);
+
+ for (page = 0; page < num_pages; page++) {
+ prlo_acc->prlo_acc_params[page].opa_valid = 0;
+ prlo_acc->prlo_acc_params[page].rpa_valid = 0;
+ prlo_acc->prlo_acc_params[page].fc4type_csp = FC_TYPE_FCP;
+ prlo_acc->prlo_acc_params[page].orig_process_assc = 0;
+ prlo_acc->prlo_acc_params[page].resp_process_assc = 0;
+ }
+
+ return bfa_os_ntohs(prlo_acc->payload_len);
+}
+
+u16
+fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id,
+ u32 s_id, u16 ox_id, u32 data_format)
+{
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ memset(rnid, 0, sizeof(struct fc_rnid_cmd_s));
+
+ rnid->els_cmd.els_code = FC_ELS_RNID;
+ rnid->node_id_data_format = data_format;
+
+ return sizeof(struct fc_rnid_cmd_s);
+}
+
+u16
+fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ u32 data_format,
+ struct fc_rnid_common_id_data_s *common_id_data,
+ struct fc_rnid_general_topology_data_s *gen_topo_data)
+{
+ memset(rnid_acc, 0, sizeof(struct fc_rnid_acc_s));
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ rnid_acc->els_cmd.els_code = FC_ELS_ACC;
+ rnid_acc->node_id_data_format = data_format;
+ rnid_acc->common_id_data_length =
+ sizeof(struct fc_rnid_common_id_data_s);
+ rnid_acc->common_id_data = *common_id_data;
+
+ if (data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) {
+ 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);
+ } else {
+ return sizeof(struct fc_rnid_acc_s) -
+ sizeof(struct fc_rnid_general_topology_data_s);
+ }
+
+}
+
+u16
+fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, u32 d_id,
+ u32 s_id, u16 ox_id)
+{
+ fc_els_req_build(fchs, d_id, s_id, ox_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);
+}
+
+u16
+fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2,
+ u32 d_id, u32 s_id, u32 *pid_list,
+ u16 npids)
+{
+ u32 dctlr_id = FC_DOMAIN_CTRLR(bfa_os_hton3b(d_id));
+ int i = 0;
+
+ fc_els_req_build(fchs, bfa_os_hton3b(dctlr_id), s_id, 0);
+
+ memset(rpsc2, 0, sizeof(struct fc_rpsc2_cmd_s));
+
+ rpsc2->els_cmd.els_code = FC_ELS_RPSC;
+ rpsc2->token = bfa_os_htonl(FC_BRCD_TOKEN);
+ rpsc2->num_pids = bfa_os_htons(npids);
+ 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)));
+}
+
+u16
+fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ struct fc_rpsc_speed_info_s *oper_speed)
+{
+ memset(rpsc_acc, 0, sizeof(struct fc_rpsc_acc_s));
+
+ fc_els_rsp_build(fchs, d_id, s_id, ox_id);
+
+ rpsc_acc->command = FC_ELS_ACC;
+ rpsc_acc->num_entries = bfa_os_htons(1);
+
+ rpsc_acc->speed_info[0].port_speed_cap =
+ bfa_os_htons(oper_speed->port_speed_cap);
+
+ rpsc_acc->speed_info[0].port_op_speed =
+ bfa_os_htons(oper_speed->port_op_speed);
+
+ return sizeof(struct fc_rpsc_acc_s);
+
+}
+
+/*
+ * TBD -
+ * . get rid of unnecessary memsets
+ */
+
+u16
+fc_logo_rsp_parse(struct fchs_s *fchs, int len)
+{
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+
+ len = len;
+ if (els_cmd->els_code != FC_ELS_ACC)
+ return FC_PARSE_FAILURE;
+
+ return FC_PARSE_OK;
+}
+
+u16
+fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size)
+{
+ struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1);
+
+ bfa_os_memcpy(pdisc, &plogi_tmpl, sizeof(struct fc_logi_s));
+
+ pdisc->els_cmd.els_code = FC_ELS_PDISC;
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ pdisc->csp.rxsz = pdisc->class3.rxsz = bfa_os_htons(pdu_size);
+ pdisc->port_name = port_name;
+ pdisc->node_name = node_name;
+
+ return sizeof(struct fc_logi_s);
+}
+
+u16
+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;
+
+ if (pdisc->els_cmd.els_code != FC_ELS_ACC)
+ return FC_PARSE_ACC_INVAL;
+
+ if (!wwn_is_equal(pdisc->port_name, port_name))
+ return FC_PARSE_PWWN_NOT_EQUAL;
+
+ if (!pdisc->class3.class_valid)
+ return FC_PARSE_NWWN_NOT_EQUAL;
+
+ if (bfa_os_ntohs(pdisc->class3.rxsz) < (FC_MIN_PDUSZ))
+ return FC_PARSE_RXSZ_INVAL;
+
+ return FC_PARSE_OK;
+}
+
+u16
+fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id,
+ int num_pages)
+{
+ struct fc_prlo_s *prlo = (struct fc_prlo_s *) (fchs + 1);
+ int page;
+
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ memset(prlo, 0, (num_pages * 16) + 4);
+ prlo->command = FC_ELS_PRLO;
+ prlo->page_len = 0x10;
+ prlo->payload_len = bfa_os_htons((num_pages * 16) + 4);
+
+ for (page = 0; page < num_pages; page++) {
+ prlo->prlo_params[page].type = FC_TYPE_FCP;
+ prlo->prlo_params[page].opa_valid = 0;
+ prlo->prlo_params[page].rpa_valid = 0;
+ prlo->prlo_params[page].orig_process_assc = 0;
+ prlo->prlo_params[page].resp_process_assc = 0;
+ }
+
+ return bfa_os_ntohs(prlo->payload_len);
+}
+
+u16
+fc_prlo_rsp_parse(struct fchs_s *fchs, int len)
+{
+ struct fc_prlo_acc_s *prlo = (struct fc_prlo_acc_s *) (fchs + 1);
+ int num_pages = 0;
+ int page = 0;
+
+ len = len;
+
+ if (prlo->command != FC_ELS_ACC)
+ return FC_PARSE_FAILURE;
+
+ num_pages = ((bfa_os_ntohs(prlo->payload_len)) - 4) / 16;
+
+ for (page = 0; page < num_pages; page++) {
+ if (prlo->prlo_acc_params[page].type != FC_TYPE_FCP)
+ return FC_PARSE_FAILURE;
+
+ if (prlo->prlo_acc_params[page].opa_valid != 0)
+ return FC_PARSE_FAILURE;
+
+ if (prlo->prlo_acc_params[page].rpa_valid != 0)
+ return FC_PARSE_FAILURE;
+
+ if (prlo->prlo_acc_params[page].orig_process_assc != 0)
+ return FC_PARSE_FAILURE;
+
+ if (prlo->prlo_acc_params[page].resp_process_assc != 0)
+ return FC_PARSE_FAILURE;
+ }
+ return FC_PARSE_OK;
+
+}
+
+u16
+fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, int num_pages,
+ enum fc_tprlo_type tprlo_type, u32 tpr_id)
+{
+ struct fc_tprlo_s *tprlo = (struct fc_tprlo_s *) (fchs + 1);
+ int page;
+
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ memset(tprlo, 0, (num_pages * 16) + 4);
+ tprlo->command = FC_ELS_TPRLO;
+ tprlo->page_len = 0x10;
+ tprlo->payload_len = bfa_os_htons((num_pages * 16) + 4);
+
+ for (page = 0; page < num_pages; page++) {
+ tprlo->tprlo_params[page].type = FC_TYPE_FCP;
+ tprlo->tprlo_params[page].opa_valid = 0;
+ tprlo->tprlo_params[page].rpa_valid = 0;
+ tprlo->tprlo_params[page].orig_process_assc = 0;
+ tprlo->tprlo_params[page].resp_process_assc = 0;
+ if (tprlo_type == FC_GLOBAL_LOGO) {
+ tprlo->tprlo_params[page].global_process_logout = 1;
+ } else if (tprlo_type == FC_TPR_LOGO) {
+ tprlo->tprlo_params[page].tpo_nport_valid = 1;
+ tprlo->tprlo_params[page].tpo_nport_id = (tpr_id);
+ }
+ }
+
+ return bfa_os_ntohs(tprlo->payload_len);
+}
+
+u16
+fc_tprlo_rsp_parse(struct fchs_s *fchs, int len)
+{
+ struct fc_tprlo_acc_s *tprlo = (struct fc_tprlo_acc_s *) (fchs + 1);
+ int num_pages = 0;
+ int page = 0;
+
+ len = len;
+
+ if (tprlo->command != FC_ELS_ACC)
+ 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;
+ if (tprlo->tprlo_acc_params[page].opa_valid != 0)
+ return FC_PARSE_OPAFLAG_INVAL;
+ if (tprlo->tprlo_acc_params[page].rpa_valid != 0)
+ return FC_PARSE_RPAFLAG_INVAL;
+ if (tprlo->tprlo_acc_params[page].orig_process_assc != 0)
+ return FC_PARSE_OPA_INVAL;
+ if (tprlo->tprlo_acc_params[page].resp_process_assc != 0)
+ return FC_PARSE_RPA_INVAL;
+ }
+ return FC_PARSE_OK;
+}
+
+enum fc_parse_status
+fc_rrq_rsp_parse(struct fchs_s *fchs, int len)
+{
+ struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+
+ len = len;
+ if (els_cmd->els_code != FC_ELS_ACC)
+ return FC_PARSE_FAILURE;
+
+ return FC_PARSE_OK;
+}
+
+u16
+fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, u32 reason_code,
+ u32 reason_expl)
+{
+ struct fc_ba_rjt_s *ba_rjt = (struct fc_ba_rjt_s *) (fchs + 1);
+
+ fc_bls_rsp_build(fchs, d_id, s_id, ox_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);
+}
+
+static void
+fc_gs_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code)
+{
+ bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+ cthdr->rev_id = CT_GS3_REVISION;
+ cthdr->gs_type = CT_GSTYPE_DIRSERVICE;
+ cthdr->gs_sub_type = CT_GSSUBTYPE_NAMESERVER;
+ cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+}
+
+static void
+fc_gs_fdmi_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code)
+{
+ bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+ cthdr->rev_id = CT_GS3_REVISION;
+ cthdr->gs_type = CT_GSTYPE_MGMTSERVICE;
+ cthdr->gs_sub_type = CT_GSSUBTYPE_HBA_MGMTSERVER;
+ cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+}
+
+static void
+fc_gs_ms_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code,
+ u8 sub_type)
+{
+ bfa_os_memset(cthdr, 0, sizeof(struct ct_hdr_s));
+ cthdr->rev_id = CT_GS3_REVISION;
+ cthdr->gs_type = CT_GSTYPE_MGMTSERVICE;
+ cthdr->gs_sub_type = sub_type;
+ cthdr->cmd_rsp_code = bfa_os_htons(cmd_code);
+}
+
+u16
+fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ wwn_t port_name)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_gidpn_req_s *gidpn =
+ (struct fcgs_gidpn_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_GID_PN);
+
+ 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);
+}
+
+u16
+fc_gpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ u32 port_id)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ fcgs_gpnid_req_t *gpnid = (fcgs_gpnid_req_t *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_GPN_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);
+}
+
+u16
+fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ u32 port_id)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ fcgs_gnnid_req_t *gnnid = (fcgs_gnnid_req_t *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_GNN_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);
+}
+
+u16
+fc_ct_rsp_parse(struct ct_hdr_s *cthdr)
+{
+ if (bfa_os_ntohs(cthdr->cmd_rsp_code) != CT_RSP_ACCEPT) {
+ if (cthdr->reason_code == CT_RSN_LOGICAL_BUSY)
+ return FC_PARSE_BUSY;
+ else
+ return FC_PARSE_FAILURE;
+ }
+
+ return FC_PARSE_OK;
+}
+
+u16
+fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, u8 set_br_reg,
+ u32 s_id, u16 ox_id)
+{
+ u32 d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER);
+
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+
+ bfa_os_memset(scr, 0, sizeof(struct fc_scr_s));
+ scr->command = FC_ELS_SCR;
+ scr->reg_func = FC_SCR_REG_FUNC_FULL;
+ if (set_br_reg)
+ scr->vu_reg_func = FC_VU_SCR_REG_FUNC_FABRIC_NAME_CHANGE;
+
+ return sizeof(struct fc_scr_s);
+}
+
+u16
+fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, u32 s_id,
+ u16 ox_id)
+{
+ u32 d_id = bfa_os_hton3b(FC_FABRIC_CONTROLLER);
+ u16 payldlen;
+
+ fc_els_req_build(fchs, d_id, s_id, ox_id);
+ rscn->command = FC_ELS_RSCN;
+ rscn->pagelen = sizeof(rscn->event[0]);
+
+ payldlen = sizeof(u32) + rscn->pagelen;
+ rscn->payldlen = bfa_os_htons(payldlen);
+
+ rscn->event[0].format = FC_RSCN_FORMAT_PORTID;
+ rscn->event[0].portid = s_id;
+
+ return sizeof(struct fc_rscn_pl_s);
+}
+
+u16
+fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ enum bfa_port_role roles)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rftid_req_s *rftid =
+ (struct fcgs_rftid_req_s *) (cthdr + 1);
+ u32 type_value, d_id = bfa_os_hton3b(FC_NAME_SERVER);
+ u8 index;
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID);
+
+ bfa_os_memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
+
+ rftid->dap = s_id;
+
+ /* By default, FCP FC4 Type is registered */
+ index = FC_TYPE_FCP >> 5;
+ type_value = 1 << (FC_TYPE_FCP % 32);
+ rftid->fc4_type[index] = bfa_os_htonl(type_value);
+
+ if (roles & BFA_PORT_ROLE_FCP_IPFC) {
+ index = FC_TYPE_IP >> 5;
+ type_value = 1 << (FC_TYPE_IP % 32);
+ rftid->fc4_type[index] |= bfa_os_htonl(type_value);
+ }
+
+ return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s);
+}
+
+u16
+fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 ox_id, u8 *fc4_bitmap,
+ u32 bitmap_size)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rftid_req_s *rftid =
+ (struct fcgs_rftid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID);
+
+ bfa_os_memset(rftid, 0, sizeof(struct fcgs_rftid_req_s));
+
+ rftid->dap = 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);
+}
+
+u16
+fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ u8 fc4_type, u8 fc4_ftrs)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rffid_req_s *rffid =
+ (struct fcgs_rffid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RFF_ID);
+
+ bfa_os_memset(rffid, 0, sizeof(struct fcgs_rffid_req_s));
+
+ rffid->dap = s_id;
+ rffid->fc4ftr_bits = fc4_ftrs;
+ rffid->fc4_type = fc4_type;
+
+ return sizeof(struct fcgs_rffid_req_s) + sizeof(struct ct_hdr_s);
+}
+
+u16
+fc_rspnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id,
+ u8 *name)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rspnid_req_s *rspnid =
+ (struct fcgs_rspnid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, ox_id);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RSPN_ID);
+
+ bfa_os_memset(rspnid, 0, sizeof(struct fcgs_rspnid_req_s));
+
+ rspnid->dap = s_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);
+}
+
+u16
+fc_gid_ft_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u8 fc4_type)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_gidft_req_s *gidft =
+ (struct fcgs_gidft_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+
+ fc_gs_cthdr_build(cthdr, s_id, GS_GID_FT);
+
+ bfa_os_memset(gidft, 0, sizeof(struct fcgs_gidft_req_s));
+ gidft->fc4_type = fc4_type;
+ gidft->domain_id = 0;
+ gidft->area_id = 0;
+
+ return sizeof(struct fcgs_gidft_req_s) + sizeof(struct ct_hdr_s);
+}
+
+u16
+fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
+ wwn_t port_name)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rpnid_req_s *rpnid =
+ (struct fcgs_rpnid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RPN_ID);
+
+ bfa_os_memset(rpnid, 0, sizeof(struct fcgs_rpnid_req_s));
+ rpnid->port_id = port_id;
+ rpnid->port_name = port_name;
+
+ return sizeof(struct fcgs_rpnid_req_s) + sizeof(struct ct_hdr_s);
+}
+
+u16
+fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
+ wwn_t node_name)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rnnid_req_s *rnnid =
+ (struct fcgs_rnnid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RNN_ID);
+
+ bfa_os_memset(rnnid, 0, sizeof(struct fcgs_rnnid_req_s));
+ rnnid->port_id = port_id;
+ rnnid->node_name = node_name;
+
+ return sizeof(struct fcgs_rnnid_req_s) + sizeof(struct ct_hdr_s);
+}
+
+u16
+fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
+ u32 cos)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rcsid_req_s *rcsid =
+ (struct fcgs_rcsid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RCS_ID);
+
+ bfa_os_memset(rcsid, 0, sizeof(struct fcgs_rcsid_req_s));
+ rcsid->port_id = port_id;
+ rcsid->cos = cos;
+
+ return sizeof(struct fcgs_rcsid_req_s) + sizeof(struct ct_hdr_s);
+}
+
+u16
+fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id,
+ u8 port_type)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_rptid_req_s *rptid =
+ (struct fcgs_rptid_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_cthdr_build(cthdr, s_id, GS_RPT_ID);
+
+ bfa_os_memset(rptid, 0, sizeof(struct fcgs_rptid_req_s));
+ rptid->port_id = port_id;
+ rptid->port_type = port_type;
+
+ return sizeof(struct fcgs_rptid_req_s) + sizeof(struct ct_hdr_s);
+}
+
+u16
+fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ struct fcgs_ganxt_req_s *ganxt =
+ (struct fcgs_ganxt_req_s *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_NAME_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_cthdr_build(cthdr, s_id, GS_GA_NXT);
+
+ 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);
+}
+
+/*
+ * Builds fc hdr and ct hdr for FDMI requests.
+ */
+u16
+fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 cmd_code)
+{
+
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+
+ 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);
+}
+
+/*
+ * Given a FC4 Type, this function returns a fc4 type bitmask
+ */
+void
+fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask)
+{
+ u8 index;
+ u32 *ptr = (u32 *) bit_mask;
+ u32 type_value;
+
+ /*
+ * @todo : Check for bitmask size
+ */
+
+ index = fc4_type >> 5;
+ type_value = 1 << (fc4_type % 32);
+ ptr[index] = bfa_os_htonl(type_value);
+
+}
+
+/*
+ * GMAL Request
+ */
+u16
+fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ fcgs_gmal_req_t *gmal = (fcgs_gmal_req_t *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GMAL_CMD,
+ CT_GSSUBTYPE_CFGSERVER);
+
+ bfa_os_memset(gmal, 0, sizeof(fcgs_gmal_req_t));
+ gmal->wwn = wwn;
+
+ return sizeof(struct ct_hdr_s) + sizeof(fcgs_gmal_req_t);
+}
+
+/*
+ * GFN (Get Fabric Name) Request
+ */
+u16
+fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn)
+{
+ struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld;
+ fcgs_gfn_req_t *gfn = (fcgs_gfn_req_t *) (cthdr + 1);
+ u32 d_id = bfa_os_hton3b(FC_MGMT_SERVER);
+
+ fc_gs_fchdr_build(fchs, d_id, s_id, 0);
+ fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GFN_CMD,
+ CT_GSSUBTYPE_CFGSERVER);
+
+ bfa_os_memset(gfn, 0, sizeof(fcgs_gfn_req_t));
+ gfn->wwn = wwn;
+
+ 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
new file mode 100644
index 000000000000..8fa7f270ef7b
--- /dev/null
+++ b/drivers/scsi/bfa/fcbuild.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * fcbuild.h - FC link service frame building and parsing routines
+ */
+
+#ifndef __FCBUILD_H__
+#define __FCBUILD_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/fc.h>
+#include <protocol/fcp.h>
+#include <protocol/ct.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_pport.h>
+
+/*
+ * Utility Macros/functions
+ */
+
+#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)
+
+#define fc_roundup(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1))
+
+/*
+ * Given the fc response length, this routine will return
+ * the length of the actual payload bytes following the CT header.
+ *
+ * Assumes the input response length does not include the crc, eof, etc.
+ */
+static inline u32
+fc_get_ctresp_pyld_len(u32 resp_len)
+{
+ return resp_len - sizeof(struct ct_hdr_s);
+}
+
+/*
+ * Convert bfa speed to rpsc speed value.
+ */
+static inline enum bfa_pport_speed
+fc_rpsc_operspeed_to_bfa_speed(enum fc_rpsc_op_speed_s speed)
+{
+ switch (speed) {
+
+ case RPSC_OP_SPEED_1G:
+ return BFA_PPORT_SPEED_1GBPS;
+
+ case RPSC_OP_SPEED_2G:
+ return BFA_PPORT_SPEED_2GBPS;
+
+ case RPSC_OP_SPEED_4G:
+ return BFA_PPORT_SPEED_4GBPS;
+
+ case RPSC_OP_SPEED_8G:
+ return BFA_PPORT_SPEED_8GBPS;
+
+ default:
+ return BFA_PPORT_SPEED_UNKNOWN;
+ }
+}
+
+/*
+ * Convert RPSC speed to bfa speed value.
+ */
+static inline enum fc_rpsc_op_speed_s
+fc_bfa_speed_to_rpsc_operspeed(enum bfa_pport_speed op_speed)
+{
+ switch (op_speed) {
+
+ case BFA_PPORT_SPEED_1GBPS:
+ return RPSC_OP_SPEED_1G;
+
+ case BFA_PPORT_SPEED_2GBPS:
+ return RPSC_OP_SPEED_2G;
+
+ case BFA_PPORT_SPEED_4GBPS:
+ return RPSC_OP_SPEED_4G;
+
+ case BFA_PPORT_SPEED_8GBPS:
+ return RPSC_OP_SPEED_8G;
+
+ default:
+ return RPSC_OP_SPEED_NOT_EST;
+ }
+}
+enum fc_parse_status {
+ FC_PARSE_OK = 0,
+ FC_PARSE_FAILURE = 1,
+ FC_PARSE_BUSY = 2,
+ FC_PARSE_LEN_INVAL,
+ FC_PARSE_ACC_INVAL,
+ FC_PARSE_PWWN_NOT_EQUAL,
+ FC_PARSE_NWWN_NOT_EQUAL,
+ FC_PARSE_RXSZ_INVAL,
+ FC_PARSE_NOT_FCP,
+ FC_PARSE_OPAFLAG_INVAL,
+ FC_PARSE_RPAFLAG_INVAL,
+ FC_PARSE_OPA_INVAL,
+ FC_PARSE_RPA_INVAL,
+
+};
+
+struct fc_templates_s {
+ struct fchs_s fc_els_req;
+ struct fchs_s fc_bls_req;
+ struct fc_logi_s plogi;
+ struct fc_rrq_s rrq;
+};
+
+void fcbuild_init(void);
+
+u16 fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name, u16 pdu_size, u8 set_npiv,
+ u8 set_auth, u16 local_bb_credits);
+u16 fc_fdisc_build(struct fchs_s *buf, struct fc_logi_s *flogi,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name, u16 pdu_size);
+u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name, u16 pdu_size,
+ u16 local_bb_credits);
+u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id,
+ u32 s_id, u16 ox_id, wwn_t port_name,
+ wwn_t node_name, u16 pdu_size);
+enum fc_parse_status fc_plogi_parse(struct fchs_s *fchs);
+u16 fc_abts_build(struct fchs_s *buf, u32 d_id, u32 s_id,
+ u16 ox_id);
+enum fc_parse_status fc_abts_rsp_parse(struct fchs_s *buf, int len);
+u16 fc_rrq_build(struct fchs_s *buf, struct fc_rrq_s *rrq, u32 d_id,
+ u32 s_id, u16 ox_id, u16 rrq_oxid);
+enum fc_parse_status fc_rrq_rsp_parse(struct fchs_s *buf, int len);
+u16 fc_rspnid_build(struct fchs_s *fchs, void *pld, u32 s_id,
+ u16 ox_id, u8 *name);
+u16 fc_rftid_build(struct fchs_s *fchs, void *pld, u32 s_id,
+ u16 ox_id, enum bfa_port_role role);
+u16 fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 ox_id, u8 *fc4_bitmap,
+ u32 bitmap_size);
+u16 fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 ox_id, u8 fc4_type, u8 fc4_ftrs);
+u16 fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 ox_id, wwn_t port_name);
+u16 fc_gpnid_build(struct fchs_s *fchs, void *pld, u32 s_id,
+ u16 ox_id, u32 port_id);
+u16 fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr,
+ u8 set_br_reg, u32 s_id, u16 ox_id);
+u16 fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id,
+ u32 s_id, u16 ox_id,
+ wwn_t port_name, wwn_t node_name, u16 pdu_size);
+
+u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ wwn_t port_name, wwn_t node_name);
+enum fc_parse_status fc_adisc_parse(struct fchs_s *fchs, void *pld,
+ u32 host_dap,
+ wwn_t node_name, wwn_t port_name);
+enum fc_parse_status fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len,
+ wwn_t port_name, wwn_t node_name);
+u16 fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ wwn_t port_name, wwn_t node_name);
+u16 fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt,
+ u32 d_id, u32 s_id, u16 ox_id,
+ u8 reason_code, u8 reason_code_expl);
+u16 fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd,
+ u32 d_id, u32 s_id, u16 ox_id);
+u16 fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id,
+ u32 s_id, u16 ox_id);
+enum fc_parse_status fc_prli_rsp_parse(struct fc_prli_s *prli, int len);
+
+u16 fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id,
+ u32 s_id, u16 ox_id,
+ enum bfa_port_role role);
+u16 fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid,
+ u32 d_id, u32 s_id, u16 ox_id,
+ u32 data_format);
+u16 fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ u32 data_format,
+ struct fc_rnid_common_id_data_s *common_id_data,
+ struct fc_rnid_general_topology_data_s *
+ gen_topo_data);
+u16 fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rps2c,
+ u32 d_id, u32 s_id,
+ u32 *pid_list, u16 npids);
+u16 fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc,
+ u32 d_id, u32 s_id, u16 ox_id);
+u16 fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ struct fc_rpsc_speed_info_s *oper_speed);
+u16 fc_gid_ft_build(struct fchs_s *fchs, void *pld, u32 s_id,
+ u8 fc4_type);
+u16 fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u32 port_id, wwn_t port_name);
+u16 fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u32 port_id, wwn_t node_name);
+u16 fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u32 port_id, u32 cos);
+u16 fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u32 port_id, u8 port_type);
+u16 fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u32 port_id);
+u16 fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo,
+ u32 d_id, u32 s_id, u16 ox_id,
+ wwn_t port_name);
+u16 fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id,
+ u32 s_id, u16 ox_id);
+u16 fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 cmd_code);
+u16 fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ wwn_t wwn);
+u16 fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ wwn_t wwn);
+void fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask);
+void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id);
+enum fc_parse_status fc_els_rsp_parse(struct fchs_s *fchs, int len);
+enum fc_parse_status fc_plogi_rsp_parse(struct fchs_s *fchs, int len,
+ wwn_t port_name);
+enum fc_parse_status fc_prli_parse(struct fc_prli_s *prli);
+enum fc_parse_status fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name,
+ wwn_t port_name);
+u16 fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ u16 rx_id);
+int fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code);
+u16 fc_tprlo_acc_build(struct fchs_s *fchs,
+ struct fc_tprlo_acc_s *tprlo_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ int num_pages);
+u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc,
+ u32 d_id, u32 s_id, u16 ox_id,
+ int num_pages);
+u16 fc_logo_rsp_parse(struct fchs_s *fchs, int len);
+u16 fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, wwn_t port_name, wwn_t node_name,
+ u16 pdu_size);
+u16 fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name);
+u16 fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, int num_pages);
+u16 fc_prlo_rsp_parse(struct fchs_s *fchs, int len);
+u16 fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, int num_pages,
+ enum fc_tprlo_type tprlo_type, u32 tpr_id);
+u16 fc_tprlo_rsp_parse(struct fchs_s *fchs, int len);
+u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id,
+ u16 ox_id, u32 reason_code,
+ u32 reason_expl);
+u16 fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id,
+ u16 ox_id, u32 port_id);
+u16 fc_ct_rsp_parse(struct ct_hdr_s *cthdr);
+u16 fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn,
+ u32 s_id, u16 ox_id);
+#endif
diff --git a/drivers/scsi/bfa/fcpim.c b/drivers/scsi/bfa/fcpim.c
new file mode 100644
index 000000000000..1f3c06efaa9e
--- /dev/null
+++ b/drivers/scsi/bfa/fcpim.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fcpim.c - FCP initiator mode i-t nexus state machine
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_fcpim.h"
+#include "fcs_rport.h"
+#include "fcs_lport.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs.h"
+#include <fcs/bfa_fcs_fcpim.h>
+#include <fcb/bfa_fcb_fcpim.h>
+#include <aen/bfa_aen_itnim.h>
+
+BFA_TRC_FILE(FCS, FCPIM);
+
+/*
+ * forward declarations
+ */
+static void bfa_fcs_itnim_timeout(void *arg);
+static void bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim);
+static void bfa_fcs_itnim_send_prli(void *itnim_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_itnim_prli_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 void bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_itnim_aen_event event);
+
+/**
+ * fcs_itnim_sm FCS itnim state machine events
+ */
+
+enum bfa_fcs_itnim_event {
+ BFA_FCS_ITNIM_SM_ONLINE = 1, /* rport online event */
+ BFA_FCS_ITNIM_SM_OFFLINE = 2, /* rport offline */
+ BFA_FCS_ITNIM_SM_FRMSENT = 3, /* prli frame is sent */
+ BFA_FCS_ITNIM_SM_RSP_OK = 4, /* good response */
+ BFA_FCS_ITNIM_SM_RSP_ERROR = 5, /* error response */
+ BFA_FCS_ITNIM_SM_TIMEOUT = 6, /* delay timeout */
+ BFA_FCS_ITNIM_SM_HCB_OFFLINE = 7, /* BFA online callback */
+ BFA_FCS_ITNIM_SM_HCB_ONLINE = 8, /* BFA offline callback */
+ BFA_FCS_ITNIM_SM_INITIATOR = 9, /* rport is initiator */
+ BFA_FCS_ITNIM_SM_DELETE = 10, /* delete event from rport */
+ BFA_FCS_ITNIM_SM_PRLO = 11, /* delete event from rport */
+};
+
+static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event);
+
+static struct bfa_sm_table_s itnim_sm_table[] = {
+ {BFA_SM(bfa_fcs_itnim_sm_offline), BFA_ITNIM_OFFLINE},
+ {BFA_SM(bfa_fcs_itnim_sm_prli_send), BFA_ITNIM_PRLI_SEND},
+ {BFA_SM(bfa_fcs_itnim_sm_prli), BFA_ITNIM_PRLI_SENT},
+ {BFA_SM(bfa_fcs_itnim_sm_prli_retry), BFA_ITNIM_PRLI_RETRY},
+ {BFA_SM(bfa_fcs_itnim_sm_hcb_online), BFA_ITNIM_HCB_ONLINE},
+ {BFA_SM(bfa_fcs_itnim_sm_online), BFA_ITNIM_ONLINE},
+ {BFA_SM(bfa_fcs_itnim_sm_hcb_offline), BFA_ITNIM_HCB_OFFLINE},
+ {BFA_SM(bfa_fcs_itnim_sm_initiator), BFA_ITNIM_INITIATIOR},
+};
+
+/**
+ * fcs_itnim_sm FCS itnim state machine
+ */
+
+static void
+bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_ONLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
+ bfa_fcs_itnim_send_prli(itnim, NULL);
+ break;
+
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_INITIATOR:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+
+}
+
+static void
+bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_FRMSENT:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli);
+ break;
+
+ case BFA_FCS_ITNIM_SM_INITIATOR:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
+ bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
+ break;
+
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_RSP_OK:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online);
+ bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec);
+ break;
+
+ case BFA_FCS_ITNIM_SM_RSP_ERROR:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_retry);
+ bfa_timer_start(itnim->fcs->bfa, &itnim->timer,
+ bfa_fcs_itnim_timeout, itnim,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcxp_discard(itnim->fcxp);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_INITIATOR:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
+ /*
+ * dont discard fcxp. accept will reach same state
+ */
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcxp_discard(itnim->fcxp);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_TIMEOUT:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send);
+ bfa_fcs_itnim_send_prli(itnim, NULL);
+ break;
+
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_timer_stop(&itnim->timer);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_INITIATOR:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator);
+ bfa_timer_stop(&itnim->timer);
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_timer_stop(&itnim->timer);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_HCB_ONLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_online);
+ bfa_fcb_itnim_online(itnim->itnim_drv);
+ bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE);
+ break;
+
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_itnim_offline(itnim->bfa_itnim);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ 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)
+ bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT);
+ else
+ bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE);
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_HCB_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/*
+ * This state is set when a discovered rport is also in intiator mode.
+ * This ITN is marked as no_op and is not active and will not be truned into
+ * online state.
+ */
+static void
+bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_fcs_itnim_event event)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_trc(itnim->fcs, event);
+
+ switch (event) {
+ case BFA_FCS_ITNIM_SM_OFFLINE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_rport_itnim_ack(itnim->rport);
+ break;
+
+ case BFA_FCS_ITNIM_SM_RSP_ERROR:
+ case BFA_FCS_ITNIM_SM_ONLINE:
+ case BFA_FCS_ITNIM_SM_INITIATOR:
+ break;
+
+ case BFA_FCS_ITNIM_SM_DELETE:
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+ bfa_fcs_itnim_free(itnim);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * itnim_private FCS ITNIM private interfaces
+ */
+
+static void
+bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim,
+ enum bfa_itnim_aen_event event)
+{
+ struct bfa_fcs_rport_s *rport = itnim->rport;
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = rport->fcs->logm;
+ wwn_t lpwwn = bfa_fcs_port_get_pwwn(rport->port);
+ wwn_t rpwwn = rport->pwwn;
+ char lpwwn_ptr[BFA_STRING_32];
+ char rpwwn_ptr[BFA_STRING_32];
+
+ /*
+ * Don't post events for well known addresses
+ */
+ if (BFA_FCS_PID_IS_WKA(rport->pid))
+ return;
+
+ wwn2str(lpwwn_ptr, lpwwn);
+ wwn2str(rpwwn_ptr, rpwwn);
+
+ switch (event) {
+ case BFA_ITNIM_AEN_ONLINE:
+ bfa_log(logmod, BFA_AEN_ITNIM_ONLINE, rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_ITNIM_AEN_OFFLINE:
+ bfa_log(logmod, BFA_AEN_ITNIM_OFFLINE, rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_ITNIM_AEN_DISCONNECT:
+ bfa_log(logmod, BFA_AEN_ITNIM_DISCONNECT, rpwwn_ptr, lpwwn_ptr);
+ break;
+ default:
+ break;
+ }
+
+ aen_data.itnim.vf_id = rport->port->fabric->vf_id;
+ aen_data.itnim.ppwwn =
+ bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(itnim->fcs));
+ aen_data.itnim.lpwwn = lpwwn;
+ aen_data.itnim.rpwwn = rpwwn;
+}
+
+static void
+bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_itnim_s *itnim = itnim_cbarg;
+ struct bfa_fcs_rport_s *rport = itnim->rport;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ int len;
+
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ itnim->stats.fcxp_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe,
+ bfa_fcs_itnim_send_prli, itnim);
+ return;
+ }
+ itnim->fcxp = fcxp;
+
+ len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), itnim->rport->pid,
+ bfa_fcs_port_get_fcid(port), 0);
+
+ bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag,
+ BFA_FALSE, FC_CLASS_3, len, &fchs,
+ bfa_fcs_itnim_prli_response, (void *)itnim, FC_MAX_PDUSZ,
+ FC_RA_TOV);
+
+ itnim->stats.prli_sent++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT);
+}
+
+static void
+bfa_fcs_itnim_prli_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_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg;
+ struct fc_els_cmd_s *els_cmd;
+ struct fc_prli_s *prli_resp;
+ struct fc_ls_rjt_s *ls_rjt;
+ struct fc_prli_params_s *sparams;
+
+ bfa_trc(itnim->fcs, req_status);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ itnim->stats.prli_rsp_err++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
+ return;
+ }
+
+ els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ if (els_cmd->els_code == FC_ELS_ACC) {
+ prli_resp = (struct fc_prli_s *) els_cmd;
+
+ if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) {
+ bfa_trc(itnim->fcs, rsp_len);
+ /*
+ * Check if this r-port is also in Initiator mode.
+ * If so, we need to set this ITN as a no-op.
+ */
+ if (prli_resp->parampage.servparams.initiator) {
+ bfa_trc(itnim->fcs, prli_resp->parampage.type);
+ itnim->rport->scsi_function =
+ BFA_RPORT_INITIATOR;
+ itnim->stats.prli_rsp_acc++;
+ bfa_sm_send_event(itnim,
+ BFA_FCS_ITNIM_SM_INITIATOR);
+ return;
+ }
+
+ itnim->stats.prli_rsp_parse_err++;
+ return;
+ }
+ itnim->rport->scsi_function = BFA_RPORT_TARGET;
+
+ sparams = &prli_resp->parampage.servparams;
+ itnim->seq_rec = sparams->retry;
+ itnim->rec_support = sparams->rec_support;
+ itnim->task_retry_id = sparams->task_retry_id;
+ itnim->conf_comp = sparams->confirm;
+
+ itnim->stats.prli_rsp_acc++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK);
+ } else {
+ ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ bfa_trc(itnim->fcs, ls_rjt->reason_code);
+ bfa_trc(itnim->fcs, ls_rjt->reason_code_expl);
+
+ itnim->stats.prli_rsp_rjt++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR);
+ }
+}
+
+static void
+bfa_fcs_itnim_timeout(void *arg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)arg;
+
+ itnim->stats.timeout++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT);
+}
+
+static void
+bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim)
+{
+ bfa_itnim_delete(itnim->bfa_itnim);
+ bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv);
+}
+
+
+
+/**
+ * itnim_public FCS ITNIM public interfaces
+ */
+
+/**
+ * Called by rport when a new rport is created.
+ *
+ * @param[in] rport - remote port.
+ */
+struct bfa_fcs_itnim_s *
+bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+ struct bfa_fcs_itnim_s *itnim;
+ struct bfad_itnim_s *itnim_drv;
+ struct bfa_itnim_s *bfa_itnim;
+
+ /*
+ * call bfad to allocate the itnim
+ */
+ bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv);
+ if (itnim == NULL) {
+ bfa_trc(port->fcs, rport->pwwn);
+ return NULL;
+ }
+
+ /*
+ * Initialize itnim
+ */
+ itnim->rport = rport;
+ itnim->fcs = rport->fcs;
+ itnim->itnim_drv = itnim_drv;
+
+ /*
+ * call BFA to create the itnim
+ */
+ bfa_itnim = bfa_itnim_create(port->fcs->bfa, rport->bfa_rport, itnim);
+
+ if (bfa_itnim == NULL) {
+ bfa_trc(port->fcs, rport->pwwn);
+ bfa_fcb_itnim_free(port->fcs->bfad, itnim_drv);
+ bfa_assert(0);
+ return NULL;
+ }
+
+ itnim->bfa_itnim = bfa_itnim;
+ itnim->seq_rec = BFA_FALSE;
+ itnim->rec_support = BFA_FALSE;
+ itnim->conf_comp = BFA_FALSE;
+ itnim->task_retry_id = BFA_FALSE;
+
+ /*
+ * Set State machine
+ */
+ bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline);
+
+ return itnim;
+}
+
+/**
+ * Called by rport to delete the instance of FCPIM.
+ *
+ * @param[in] rport - remote port.
+ */
+void
+bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pid);
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE);
+}
+
+/**
+ * Notification from rport that PLOGI is complete to initiate FC-4 session.
+ */
+void
+bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim)
+{
+ itnim->stats.onlines++;
+
+ if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid)) {
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_ONLINE);
+ } else {
+ /*
+ * For well known addresses, we set the itnim to initiator
+ * state
+ */
+ itnim->stats.initiator++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
+ }
+}
+
+/**
+ * Called by rport to handle a remote device offline.
+ */
+void
+bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim)
+{
+ itnim->stats.offlines++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE);
+}
+
+/**
+ * Called by rport when remote port is known to be an initiator from
+ * PRLI received.
+ */
+void
+bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pid);
+ itnim->stats.initiator++;
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR);
+}
+
+/**
+ * Called by rport to check if the itnim is online.
+ */
+bfa_status_t
+bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim)
+{
+ bfa_trc(itnim->fcs, itnim->rport->pid);
+ switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) {
+ case BFA_ITNIM_ONLINE:
+ case BFA_ITNIM_INITIATIOR:
+ return BFA_STATUS_OK;
+
+ default:
+ return BFA_STATUS_NO_FCPIM_NEXUS;
+
+ }
+}
+
+/**
+ * BFA completion callback for bfa_itnim_online().
+ */
+void
+bfa_cb_itnim_online(void *cbarg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cbarg;
+
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE);
+}
+
+/**
+ * BFA completion callback for bfa_itnim_offline().
+ */
+void
+bfa_cb_itnim_offline(void *cb_arg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
+
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE);
+}
+
+/**
+ * Mark the beginning of PATH TOV handling. IO completion callbacks
+ * are still pending.
+ */
+void
+bfa_cb_itnim_tov_begin(void *cb_arg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
+
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_fcb_itnim_tov_begin(itnim->itnim_drv);
+}
+
+/**
+ * Mark the end of PATH TOV handling. All pending IOs are already cleaned up.
+ */
+void
+bfa_cb_itnim_tov(void *cb_arg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
+
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_fcb_itnim_tov(itnim->itnim_drv);
+}
+
+/**
+ * BFA notification to FCS/driver for second level error recovery.
+ *
+ * Atleast one I/O request has timedout and target is unresponsive to
+ * repeated abort requests. Second level error recovery should be initiated
+ * by starting implicit logout and recovery procedures.
+ */
+void
+bfa_cb_itnim_sler(void *cb_arg)
+{
+ struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *)cb_arg;
+
+ itnim->stats.sler++;
+ bfa_trc(itnim->fcs, itnim->rport->pwwn);
+ bfa_fcs_rport_logo_imp(itnim->rport);
+}
+
+struct bfa_fcs_itnim_s *
+bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn)
+{
+ struct bfa_fcs_rport_s *rport;
+ rport = bfa_fcs_rport_lookup(port, rpwwn);
+
+ if (!rport)
+ return NULL;
+
+ bfa_assert(rport->itnim != NULL);
+ return rport->itnim;
+}
+
+bfa_status_t
+bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
+ struct bfa_itnim_attr_s *attr)
+{
+ struct bfa_fcs_itnim_s *itnim = NULL;
+
+ itnim = bfa_fcs_itnim_lookup(port, rpwwn);
+
+ if (itnim == NULL)
+ return BFA_STATUS_NO_FCPIM_NEXUS;
+
+ attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm);
+ attr->retry = itnim->seq_rec;
+ attr->rec_support = itnim->rec_support;
+ attr->conf_comp = itnim->conf_comp;
+ attr->task_retry_id = itnim->task_retry_id;
+
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
+ struct bfa_itnim_stats_s *stats)
+{
+ struct bfa_fcs_itnim_s *itnim = NULL;
+
+ bfa_assert(port != NULL);
+
+ itnim = bfa_fcs_itnim_lookup(port, rpwwn);
+
+ if (itnim == NULL)
+ return BFA_STATUS_NO_FCPIM_NEXUS;
+
+ bfa_os_memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s));
+
+ return BFA_STATUS_OK;
+}
+
+bfa_status_t
+bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port, wwn_t rpwwn)
+{
+ struct bfa_fcs_itnim_s *itnim = NULL;
+
+ bfa_assert(port != NULL);
+
+ itnim = bfa_fcs_itnim_lookup(port, rpwwn);
+
+ if (itnim == NULL)
+ return BFA_STATUS_NO_FCPIM_NEXUS;
+
+ bfa_os_memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s));
+ return BFA_STATUS_OK;
+}
+
+void
+bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs,
+ u16 len)
+{
+ struct fc_els_cmd_s *els_cmd;
+
+ bfa_trc(itnim->fcs, fchs->type);
+
+ if (fchs->type != FC_TYPE_ELS)
+ return;
+
+ els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+
+ bfa_trc(itnim->fcs, els_cmd->els_code);
+
+ switch (els_cmd->els_code) {
+ case FC_ELS_PRLO:
+ /* bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_PRLO); */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+void
+bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim)
+{
+}
+
+void
+bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim)
+{
+}
+
+/**
+ * Module initialization
+ */
+void
+bfa_fcs_fcpim_modinit(struct bfa_fcs_s *fcs)
+{
+}
+
+/**
+ * Module cleanup
+ */
+void
+bfa_fcs_fcpim_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
+
+
diff --git a/drivers/scsi/bfa/fcptm.c b/drivers/scsi/bfa/fcptm.c
new file mode 100644
index 000000000000..8c8b08c72e7a
--- /dev/null
+++ b/drivers/scsi/bfa/fcptm.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * This file contains dummy FCPTM routines to aid in Initiator Mode only
+ * compilation of OS driver.
+ *
+ */
+
+#include "bfa_os_inc.h"
+#include "fcs_rport.h"
+#include "fcs_fcptm.h"
+#include "fcs/bfa_fcs_rport.h"
+
+struct bfa_fcs_tin_s *
+bfa_fcs_tin_create(struct bfa_fcs_rport_s *rport)
+{
+ return NULL;
+}
+
+void
+bfa_fcs_tin_delete(struct bfa_fcs_tin_s *tin)
+{
+}
+
+void
+bfa_fcs_tin_rport_offline(struct bfa_fcs_tin_s *tin)
+{
+}
+
+void
+bfa_fcs_tin_rport_online(struct bfa_fcs_tin_s *tin)
+{
+}
+
+void
+bfa_fcs_tin_rx_prli(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, u16 len)
+{
+}
+
+void
+bfa_fcs_fcptm_uf_recv(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs, u16 len)
+{
+}
+
+void
+bfa_fcs_tin_pause(struct bfa_fcs_tin_s *tin)
+{
+}
+
+void
+bfa_fcs_tin_resume(struct bfa_fcs_tin_s *tin)
+{
+}
diff --git a/drivers/scsi/bfa/fcs.h b/drivers/scsi/bfa/fcs.h
new file mode 100644
index 000000000000..8d08230e6295
--- /dev/null
+++ b/drivers/scsi/bfa/fcs.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fcs.h FCS module functions
+ */
+
+
+#ifndef __FCS_H__
+#define __FCS_H__
+
+#define __fcs_min_cfg(__fcs) ((__fcs)->min_cfg)
+
+void bfa_fcs_modexit_comp(struct bfa_fcs_s *fcs);
+
+#endif /* __FCS_H__ */
diff --git a/drivers/scsi/bfa/fcs_auth.h b/drivers/scsi/bfa/fcs_auth.h
new file mode 100644
index 000000000000..65d155fea3d7
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_auth.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fcs_uf.h FCS unsolicited frame receive
+ */
+
+
+#ifndef __FCS_AUTH_H__
+#define __FCS_AUTH_H__
+
+#include <fcs/bfa_fcs.h>
+#include <fcs/bfa_fcs_vport.h>
+#include <fcs/bfa_fcs_lport.h>
+
+/*
+ * fcs friend functions: only between fcs modules
+ */
+void bfa_fcs_auth_uf_recv(struct bfa_fcs_fabric_s *fabric, int len);
+void bfa_fcs_auth_start(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_auth_stop(struct bfa_fcs_fabric_s *fabric);
+
+#endif /* __FCS_UF_H__ */
diff --git a/drivers/scsi/bfa/fcs_fabric.h b/drivers/scsi/bfa/fcs_fabric.h
new file mode 100644
index 000000000000..eee960820f86
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_fabric.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fcs_lport.h FCS logical port interfaces
+ */
+
+#ifndef __FCS_FABRIC_H__
+#define __FCS_FABRIC_H__
+
+#include <fcs/bfa_fcs.h>
+#include <fcs/bfa_fcs_vport.h>
+#include <fcs/bfa_fcs_lport.h>
+
+/*
+* fcs friend functions: only between fcs modules
+ */
+void bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fabric_modsusp(struct bfa_fcs_s *fcs);
+void bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric,
+ struct bfa_fcs_vport_s *vport);
+void bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric,
+ struct bfa_fcs_vport_s *vport);
+int bfa_fcs_fabric_is_online(struct bfa_fcs_fabric_s *fabric);
+struct bfa_fcs_vport_s *bfa_fcs_fabric_vport_lookup(
+ struct bfa_fcs_fabric_s *fabric, wwn_t pwwn);
+void bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs);
+void bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric,
+ struct fchs_s *fchs, u16 len);
+u16 bfa_fcs_fabric_vport_count(struct bfa_fcs_fabric_s *fabric);
+bfa_boolean_t bfa_fcs_fabric_is_loopback(struct bfa_fcs_fabric_s *fabric);
+enum bfa_pport_type bfa_fcs_fabric_port_type(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric);
+void bfa_fcs_fabric_port_delete_comp(struct bfa_fcs_fabric_s *fabric);
+
+bfa_status_t bfa_fcs_fabric_addvf(struct bfa_fcs_fabric_s *vf,
+ struct bfa_fcs_s *fcs, struct bfa_port_cfg_s *port_cfg,
+ struct bfad_vf_s *vf_drv);
+void bfa_fcs_auth_finished(struct bfa_fcs_fabric_s *fabric,
+ enum auth_status status);
+
+void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric,
+ wwn_t fabric_name);
+#endif /* __FCS_FABRIC_H__ */
diff --git a/drivers/scsi/bfa/fcs_fcpim.h b/drivers/scsi/bfa/fcs_fcpim.h
new file mode 100644
index 000000000000..61e9e2687de3
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_fcpim.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __FCS_FCPIM_H__
+#define __FCS_FCPIM_H__
+
+#include <defs/bfa_defs_port.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_rport.h>
+
+/*
+ * Following routines are from FCPIM and will be called by rport.
+ */
+struct bfa_fcs_itnim_s *bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim);
+void bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim);
+void bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim);
+bfa_status_t bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim);
+
+void bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim);
+void bfa_fcs_itnim_pause(struct bfa_fcs_itnim_s *itnim);
+void bfa_fcs_itnim_resume(struct bfa_fcs_itnim_s *itnim);
+
+/*
+ * Modudle init/cleanup routines.
+ */
+void bfa_fcs_fcpim_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fcpim_modexit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, struct fchs_s *fchs,
+ u16 len);
+#endif /* __FCS_FCPIM_H__ */
diff --git a/drivers/scsi/bfa/fcs_fcptm.h b/drivers/scsi/bfa/fcs_fcptm.h
new file mode 100644
index 000000000000..ffff0829fd31
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_fcptm.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __FCS_FCPTM_H__
+#define __FCS_FCPTM_H__
+
+#include <defs/bfa_defs_port.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_rport.h>
+
+/*
+ * Following routines are from FCPTM and will be called by rport.
+ */
+struct bfa_fcs_tin_s *bfa_fcs_tin_create(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_tin_rport_offline(struct bfa_fcs_tin_s *tin);
+void bfa_fcs_tin_rport_online(struct bfa_fcs_tin_s *tin);
+void bfa_fcs_tin_delete(struct bfa_fcs_tin_s *tin);
+void bfa_fcs_tin_rx_prli(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs,
+ u16 len);
+void bfa_fcs_tin_pause(struct bfa_fcs_tin_s *tin);
+void bfa_fcs_tin_resume(struct bfa_fcs_tin_s *tin);
+
+/*
+ * Modudle init/cleanup routines.
+ */
+void bfa_fcs_fcptm_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fcptm_modexit(struct bfa_fcs_s *fcs);
+void bfa_fcs_fcptm_uf_recv(struct bfa_fcs_tin_s *tin, struct fchs_s *fchs,
+ u16 len);
+
+#endif /* __FCS_FCPTM_H__ */
diff --git a/drivers/scsi/bfa/fcs_fcxp.h b/drivers/scsi/bfa/fcs_fcxp.h
new file mode 100644
index 000000000000..8277fe9c2b70
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_fcxp.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fcs_fcxp.h FCXP helper macros for FCS
+ */
+
+
+#ifndef __FCS_FCXP_H__
+#define __FCS_FCXP_H__
+
+#define bfa_fcs_fcxp_alloc(__fcs) \
+ bfa_fcxp_alloc(NULL, (__fcs)->bfa, 0, 0, NULL, NULL, NULL, NULL)
+
+#endif /* __FCS_FCXP_H__ */
diff --git a/drivers/scsi/bfa/fcs_lport.h b/drivers/scsi/bfa/fcs_lport.h
new file mode 100644
index 000000000000..ae744ba35671
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_lport.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fcs_lport.h FCS logical port interfaces
+ */
+
+#ifndef __FCS_LPORT_H__
+#define __FCS_LPORT_H__
+
+#define __VPORT_H__
+#include <defs/bfa_defs_port.h>
+#include <bfa_svc.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_rport.h>
+#include <fcs/bfa_fcs_vport.h>
+#include <fcs_fabric.h>
+#include <fcs_ms.h>
+#include <cs/bfa_q.h>
+#include <fcbuild.h>
+
+/*
+ * PID used in P2P/N2N ( In Big Endian)
+ */
+#define N2N_LOCAL_PID 0x010000
+#define N2N_REMOTE_PID 0x020000
+
+/*
+ * Misc Timeouts
+ */
+/*
+ * To be used when spawning a timer before retrying a failed command. Milli
+ * Secs.
+ */
+#define BFA_FCS_RETRY_TIMEOUT 2000
+
+/*
+ * Check for Port/Vport Mode/Role
+ */
+#define BFA_FCS_VPORT_IS_INITIATOR_MODE(port) \
+ (port->port_cfg.roles & BFA_PORT_ROLE_FCP_IM)
+
+#define BFA_FCS_VPORT_IS_TARGET_MODE(port) \
+ (port->port_cfg.roles & BFA_PORT_ROLE_FCP_TM)
+
+#define BFA_FCS_VPORT_IS_IPFC_MODE(port) \
+ (port->port_cfg.roles & BFA_PORT_ROLE_FCP_IPFC)
+
+/*
+ * Is this a Well Known Address
+ */
+#define BFA_FCS_PID_IS_WKA(pid) ((bfa_os_ntoh3b(pid) > 0xFFF000) ? 1 : 0)
+
+/*
+ * Pointer to elements within Port
+ */
+#define BFA_FCS_GET_HAL_FROM_PORT(port) (port->fcs->bfa)
+#define BFA_FCS_GET_NS_FROM_PORT(port) (&port->port_topo.pfab.ns)
+#define BFA_FCS_GET_SCN_FROM_PORT(port) (&port->port_topo.pfab.scn)
+#define BFA_FCS_GET_MS_FROM_PORT(port) (&port->port_topo.pfab.ms)
+#define BFA_FCS_GET_FDMI_FROM_PORT(port) (&port->port_topo.pfab.ms.fdmi)
+
+/*
+ * handler for unsolicied frames
+ */
+void bfa_fcs_port_uf_recv(struct bfa_fcs_port_s *lport, struct fchs_s *fchs,
+ u16 len);
+
+/*
+ * Following routines will be called by Fabric to indicate port
+ * online/offline to vport.
+ */
+void bfa_fcs_lport_init(struct bfa_fcs_port_s *lport, struct bfa_fcs_s *fcs,
+ u16 vf_id, struct bfa_port_cfg_s *port_cfg,
+ struct bfa_fcs_vport_s *vport);
+void bfa_fcs_port_online(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_offline(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_delete(struct bfa_fcs_port_s *port);
+bfa_boolean_t bfa_fcs_port_is_online(struct bfa_fcs_port_s *port);
+
+/*
+ * Lookup rport based on PID
+ */
+struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_pid(
+ struct bfa_fcs_port_s *port, u32 pid);
+
+/*
+ * Lookup rport based on PWWN
+ */
+struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_pwwn(
+ struct bfa_fcs_port_s *port, wwn_t pwwn);
+struct bfa_fcs_rport_s *bfa_fcs_port_get_rport_by_nwwn(
+ struct bfa_fcs_port_s *port, wwn_t nwwn);
+void bfa_fcs_port_add_rport(struct bfa_fcs_port_s *port,
+ struct bfa_fcs_rport_s *rport);
+void bfa_fcs_port_del_rport(struct bfa_fcs_port_s *port,
+ struct bfa_fcs_rport_s *rport);
+
+void bfa_fcs_port_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_port_modexit(struct bfa_fcs_s *fcs);
+void bfa_fcs_port_lip(struct bfa_fcs_port_s *port);
+
+#endif /* __FCS_LPORT_H__ */
diff --git a/drivers/scsi/bfa/fcs_ms.h b/drivers/scsi/bfa/fcs_ms.h
new file mode 100644
index 000000000000..b6a8c12876f4
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_ms.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fcs_ms.h FCS ms interfaces
+ */
+#ifndef __FCS_MS_H__
+#define __FCS_MS_H__
+
+/* MS FCS routines */
+void bfa_fcs_port_ms_init(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_ms_offline(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_ms_online(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_ms_fabric_rscn(struct bfa_fcs_port_s *port);
+
+/* FDMI FCS routines */
+void bfa_fcs_port_fdmi_init(struct bfa_fcs_port_ms_s *ms);
+void bfa_fcs_port_fdmi_offline(struct bfa_fcs_port_ms_s *ms);
+void bfa_fcs_port_fdmi_online(struct bfa_fcs_port_ms_s *ms);
+
+#endif
diff --git a/drivers/scsi/bfa/fcs_port.h b/drivers/scsi/bfa/fcs_port.h
new file mode 100644
index 000000000000..abb65191dd27
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_port.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fcs_pport.h FCS physical port interfaces
+ */
+
+
+#ifndef __FCS_PPORT_H__
+#define __FCS_PPORT_H__
+
+/*
+ * fcs friend functions: only between fcs modules
+ */
+void bfa_fcs_pport_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_pport_modexit(struct bfa_fcs_s *fcs);
+
+#endif /* __FCS_PPORT_H__ */
diff --git a/drivers/scsi/bfa/fcs_rport.h b/drivers/scsi/bfa/fcs_rport.h
new file mode 100644
index 000000000000..f601e9d74236
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_rport.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fcs_rport.h FCS rport interfaces and defines
+ */
+
+#ifndef __FCS_RPORT_H__
+#define __FCS_RPORT_H__
+
+#include <fcs/bfa_fcs_rport.h>
+
+void bfa_fcs_rport_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_rport_modexit(struct bfa_fcs_s *fcs);
+
+void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
+ u16 len);
+void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport);
+
+struct bfa_fcs_rport_s *bfa_fcs_rport_create(struct bfa_fcs_port_s *port,
+ u32 pid);
+void bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_start(struct bfa_fcs_port_s *port, struct fchs_s *rx_fchs,
+ struct fc_logi_s *plogi_rsp);
+void bfa_fcs_rport_plogi_create(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs,
+ struct fc_logi_s *plogi);
+void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
+ struct fc_logi_s *plogi);
+void bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_itntm_ack(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_fcptm_offline_done(struct bfa_fcs_rport_s *rport);
+int bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport);
+struct bfa_fcs_rport_s *bfa_fcs_rport_create_by_wwn(struct bfa_fcs_port_s *port,
+ wwn_t wwn);
+
+
+/* Rport Features */
+void bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport);
+
+#endif /* __FCS_RPORT_H__ */
diff --git a/drivers/scsi/bfa/fcs_trcmod.h b/drivers/scsi/bfa/fcs_trcmod.h
new file mode 100644
index 000000000000..41b5ae8d7644
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_trcmod.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fcs_trcmod.h BFA FCS trace modules
+ */
+
+#ifndef __FCS_TRCMOD_H__
+#define __FCS_TRCMOD_H__
+
+#include <cs/bfa_trc.h>
+
+/*
+ * !!! Only append to the enums defined here to avoid any versioning
+ * !!! needed between trace utility and driver version
+ */
+enum {
+ BFA_TRC_FCS_FABRIC = 1,
+ BFA_TRC_FCS_VFAPI = 2,
+ BFA_TRC_FCS_PORT = 3,
+ BFA_TRC_FCS_VPORT = 4,
+ BFA_TRC_FCS_VP_API = 5,
+ BFA_TRC_FCS_VPS = 6,
+ BFA_TRC_FCS_RPORT = 7,
+ BFA_TRC_FCS_FCPIM = 8,
+ BFA_TRC_FCS_FCPTM = 9,
+ BFA_TRC_FCS_NS = 10,
+ BFA_TRC_FCS_SCN = 11,
+ BFA_TRC_FCS_LOOP = 12,
+ BFA_TRC_FCS_UF = 13,
+ BFA_TRC_FCS_PPORT = 14,
+ BFA_TRC_FCS_FCPIP = 15,
+ BFA_TRC_FCS_PORT_API = 16,
+ BFA_TRC_FCS_RPORT_API = 17,
+ BFA_TRC_FCS_AUTH = 18,
+ BFA_TRC_FCS_N2N = 19,
+ BFA_TRC_FCS_MS = 20,
+ BFA_TRC_FCS_FDMI = 21,
+ BFA_TRC_FCS_RPORT_FTRS = 22,
+};
+
+#endif /* __FCS_TRCMOD_H__ */
diff --git a/drivers/scsi/bfa/fcs_uf.h b/drivers/scsi/bfa/fcs_uf.h
new file mode 100644
index 000000000000..96f1bdcb31ed
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_uf.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * fcs_uf.h FCS unsolicited frame receive
+ */
+
+
+#ifndef __FCS_UF_H__
+#define __FCS_UF_H__
+
+/*
+ * fcs friend functions: only between fcs modules
+ */
+void bfa_fcs_uf_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_uf_modexit(struct bfa_fcs_s *fcs);
+
+#endif /* __FCS_UF_H__ */
diff --git a/drivers/scsi/bfa/fcs_vport.h b/drivers/scsi/bfa/fcs_vport.h
new file mode 100644
index 000000000000..9e80b6a97b7f
--- /dev/null
+++ b/drivers/scsi/bfa/fcs_vport.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __FCS_VPORT_H__
+#define __FCS_VPORT_H__
+
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_vport.h>
+#include <defs/bfa_defs_pci.h>
+
+/*
+ * Modudle init/cleanup routines.
+ */
+
+void bfa_fcs_vport_modinit(struct bfa_fcs_s *fcs);
+void bfa_fcs_vport_modexit(struct bfa_fcs_s *fcs);
+
+void bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport);
+void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport);
+void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport);
+void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport);
+u32 bfa_fcs_vport_get_max(struct bfa_fcs_s *fcs);
+
+#endif /* __FCS_VPORT_H__ */
+
diff --git a/drivers/scsi/bfa/fdmi.c b/drivers/scsi/bfa/fdmi.c
new file mode 100644
index 000000000000..df2a1e54e16b
--- /dev/null
+++ b/drivers/scsi/bfa/fdmi.c
@@ -0,0 +1,1223 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * port_api.c BFA FCS port
+ */
+
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "lport_priv.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include <fcs/bfa_fcs_fdmi.h>
+
+BFA_TRC_FILE(FCS, FDMI);
+
+#define BFA_FCS_FDMI_CMD_MAX_RETRIES 2
+
+/*
+ * forward declarations
+ */
+static void bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_fdmi_send_rprt(void *fdmi_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_fdmi_send_rpa(void *fdmi_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_fdmi_rhba_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 void bfa_fcs_port_fdmi_rprt_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 void bfa_fcs_port_fdmi_rpa_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 void bfa_fcs_port_fdmi_timeout(void *arg);
+static u16 bfa_fcs_port_fdmi_build_rhba_pyld(
+ struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
+static u16 bfa_fcs_port_fdmi_build_rprt_pyld(
+ struct bfa_fcs_port_fdmi_s *fdmi, u8 *pyld);
+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);
+static void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
+ struct bfa_fcs_fdmi_hba_attr_s *hba_attr);
+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
+ */
+
+/**
+ * FDMI State Machine events
+ */
+enum port_fdmi_event {
+ FDMISM_EVENT_PORT_ONLINE = 1,
+ FDMISM_EVENT_PORT_OFFLINE = 2,
+ FDMISM_EVENT_RSP_OK = 4,
+ FDMISM_EVENT_RSP_ERROR = 5,
+ FDMISM_EVENT_TIMEOUT = 6,
+ FDMISM_EVENT_RHBA_SENT = 7,
+ FDMISM_EVENT_RPRT_SENT = 8,
+ FDMISM_EVENT_RPA_SENT = 9,
+};
+
+static void bfa_fcs_port_fdmi_sm_offline(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_sending_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rhba_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_sending_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rprt_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_sending_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+static void bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event);
+/**
+ * Start in offline state - awaiting MS to send start.
+ */
+static void
+bfa_fcs_port_fdmi_sm_offline(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ fdmi->retry_cnt = 0;
+
+ switch (event) {
+ case FDMISM_EVENT_PORT_ONLINE:
+ if (port->vport) {
+ /*
+ * For Vports, register a new port.
+ */
+ bfa_sm_set_state(fdmi,
+ bfa_fcs_port_fdmi_sm_sending_rprt);
+ bfa_fcs_port_fdmi_send_rprt(fdmi, NULL);
+ } else {
+ /*
+ * For a base port, we should first register the HBA
+ * atribute. The HBA attribute also contains the base
+ * port registration.
+ */
+ bfa_sm_set_state(fdmi,
+ bfa_fcs_port_fdmi_sm_sending_rhba);
+ bfa_fcs_port_fdmi_send_rhba(fdmi, NULL);
+ }
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_sending_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case FDMISM_EVENT_RHBA_SENT:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rhba);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rhba(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case FDMISM_EVENT_RSP_ERROR:
+ /*
+ * if max retries have not been reached, start timer for a
+ * delayed retry
+ */
+ if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rhba_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->timer, bfa_fcs_port_fdmi_timeout,
+ fdmi, BFA_FCS_RETRY_TIMEOUT);
+ } else {
+ /*
+ * set state to offline
+ */
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ }
+ break;
+
+ case FDMISM_EVENT_RSP_OK:
+ /*
+ * Initiate Register Port Attributes
+ */
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rpa);
+ fdmi->retry_cnt = 0;
+ bfa_fcs_port_fdmi_send_rpa(fdmi, NULL);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_fcxp_discard(fdmi->fcxp);
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rhba_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case FDMISM_EVENT_TIMEOUT:
+ /*
+ * Retry Timer Expired. Re-send
+ */
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rhba);
+ bfa_fcs_port_fdmi_send_rhba(fdmi, NULL);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_timer_stop(&fdmi->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/*
+* RPRT : Register Port
+ */
+static void
+bfa_fcs_port_fdmi_sm_sending_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case FDMISM_EVENT_RPRT_SENT:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rprt);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rprt(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case FDMISM_EVENT_RSP_ERROR:
+ /*
+ * if max retries have not been reached, start timer for a
+ * delayed retry
+ */
+ if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rprt_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->timer, bfa_fcs_port_fdmi_timeout,
+ fdmi, BFA_FCS_RETRY_TIMEOUT);
+
+ } else {
+ /*
+ * set state to offline
+ */
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ fdmi->retry_cnt = 0;
+ }
+ break;
+
+ case FDMISM_EVENT_RSP_OK:
+ fdmi->retry_cnt = 0;
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_online);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_fcxp_discard(fdmi->fcxp);
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rprt_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case FDMISM_EVENT_TIMEOUT:
+ /*
+ * Retry Timer Expired. Re-send
+ */
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rprt);
+ bfa_fcs_port_fdmi_send_rprt(fdmi, NULL);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_timer_stop(&fdmi->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/*
+ * Register Port Attributes
+ */
+static void
+bfa_fcs_port_fdmi_sm_sending_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case FDMISM_EVENT_RPA_SENT:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rpa);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rpa(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case FDMISM_EVENT_RSP_ERROR:
+ /*
+ * if max retries have not been reached, start timer for a
+ * delayed retry
+ */
+ if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) {
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_rpa_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port),
+ &fdmi->timer, bfa_fcs_port_fdmi_timeout,
+ fdmi, BFA_FCS_RETRY_TIMEOUT);
+ } else {
+ /*
+ * set state to offline
+ */
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ fdmi->retry_cnt = 0;
+ }
+ break;
+
+ case FDMISM_EVENT_RSP_OK:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_online);
+ fdmi->retry_cnt = 0;
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_fcxp_discard(fdmi->fcxp);
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_rpa_retry(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case FDMISM_EVENT_TIMEOUT:
+ /*
+ * Retry Timer Expired. Re-send
+ */
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_sending_rpa);
+ bfa_fcs_port_fdmi_send_rpa(fdmi, NULL);
+ break;
+
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ bfa_timer_stop(&fdmi->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_fdmi_sm_online(struct bfa_fcs_port_fdmi_s *fdmi,
+ enum port_fdmi_event event)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+ bfa_trc(port->fcs, event);
+
+ switch (event) {
+ case FDMISM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+/**
+* RHBA : Register HBA Attributes.
+ */
+static void
+bfa_fcs_port_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg;
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct fchs_s fchs;
+ int len, attr_len;
+ struct bfa_fcxp_s *fcxp;
+ u8 *pyld;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
+ bfa_fcs_port_fdmi_send_rhba, fdmi);
+ return;
+ }
+ fdmi->fcxp = fcxp;
+
+ pyld = bfa_fcxp_get_reqbuf(fcxp);
+ bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+
+ len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port),
+ FDMI_RHBA);
+
+ attr_len = bfa_fcs_port_fdmi_build_rhba_pyld(fdmi,
+ (u8 *) ((struct ct_hdr_s *) pyld + 1));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, (len + attr_len), &fchs,
+ bfa_fcs_port_fdmi_rhba_response, (void *)fdmi,
+ FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT);
+}
+
+static u16
+bfa_fcs_port_fdmi_build_rhba_pyld(struct bfa_fcs_port_fdmi_s *fdmi,
+ u8 *pyld)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct bfa_fcs_fdmi_hba_attr_s hba_attr; /* @todo */
+ struct bfa_fcs_fdmi_hba_attr_s *fcs_hba_attr = &hba_attr; /* @todo */
+ struct fdmi_rhba_s *rhba = (struct fdmi_rhba_s *) pyld;
+ struct fdmi_attr_s *attr;
+ u8 *curr_ptr;
+ u16 len, count;
+
+ /*
+ * get hba attributes
+ */
+ bfa_fcs_fdmi_get_hbaattr(fdmi, fcs_hba_attr);
+
+ rhba->hba_id = bfa_fcs_port_get_pwwn(port);
+ rhba->port_list.num_ports = bfa_os_htonl(1);
+ rhba->port_list.port_entry = bfa_fcs_port_get_pwwn(port);
+
+ len = sizeof(rhba->hba_id) + sizeof(rhba->port_list);
+
+ count = 0;
+ len += sizeof(rhba->hba_attr_blk.attr_count);
+
+ /*
+ * fill out the invididual entries of the HBA attrib Block
+ */
+ curr_ptr = (u8 *) &rhba->hba_attr_blk.hba_attr;
+
+ /*
+ * Node Name
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_NODENAME);
+ attr->len = sizeof(wwn_t);
+ memcpy(attr->value, &bfa_fcs_port_get_nwwn(port), attr->len);
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Manufacturer
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MANUFACTURER);
+ attr->len = (u16) strlen(fcs_hba_attr->manufacturer);
+ memcpy(attr->value, fcs_hba_attr->manufacturer, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Serial Number
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_SERIALNUM);
+ attr->len = (u16) strlen(fcs_hba_attr->serial_num);
+ memcpy(attr->value, fcs_hba_attr->serial_num, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Model
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL);
+ attr->len = (u16) strlen(fcs_hba_attr->model);
+ memcpy(attr->value, fcs_hba_attr->model, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Model Desc
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MODEL_DESC);
+ attr->len = (u16) strlen(fcs_hba_attr->model_desc);
+ memcpy(attr->value, fcs_hba_attr->model_desc, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * H/W Version
+ */
+ if (fcs_hba_attr->hw_version[0] != '\0') {
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_HW_VERSION);
+ attr->len = (u16) strlen(fcs_hba_attr->hw_version);
+ memcpy(attr->value, fcs_hba_attr->hw_version, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+ }
+
+ /*
+ * Driver Version
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_DRIVER_VERSION);
+ attr->len = (u16) strlen(fcs_hba_attr->driver_version);
+ memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Option Rom Version
+ */
+ if (fcs_hba_attr->option_rom_ver[0] != '\0') {
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_ROM_VERSION);
+ attr->len = (u16) strlen(fcs_hba_attr->option_rom_ver);
+ memcpy(attr->value, fcs_hba_attr->option_rom_ver, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+ }
+
+ /*
+ * f/w Version = driver version
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_FW_VERSION);
+ attr->len = (u16) strlen(fcs_hba_attr->driver_version);
+ memcpy(attr->value, fcs_hba_attr->driver_version, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * OS Name
+ */
+ if (fcs_hba_attr->os_name[0] != '\0') {
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_OS_NAME);
+ attr->len = (u16) strlen(fcs_hba_attr->os_name);
+ memcpy(attr->value, fcs_hba_attr->os_name, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+ }
+
+ /*
+ * MAX_CT_PAYLOAD
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_HBA_ATTRIB_MAX_CT);
+ attr->len = sizeof(fcs_hba_attr->max_ct_pyld);
+ memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, attr->len);
+ len += attr->len;
+ count++;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Update size of payload
+ */
+ len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
+
+ rhba->hba_attr_blk.attr_count = bfa_os_htonl(count);
+ return len;
+}
+
+static void
+bfa_fcs_port_fdmi_rhba_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_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg;
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct ct_hdr_s *cthdr = NULL;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
+ cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
+ return;
+ }
+
+ bfa_trc(port->fcs, cthdr->reason_code);
+ bfa_trc(port->fcs, cthdr->exp_code);
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
+}
+
+/**
+* RPRT : Register Port
+ */
+static void
+bfa_fcs_port_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg;
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct fchs_s fchs;
+ u16 len, attr_len;
+ struct bfa_fcxp_s *fcxp;
+ u8 *pyld;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
+ bfa_fcs_port_fdmi_send_rprt, fdmi);
+ return;
+ }
+ fdmi->fcxp = fcxp;
+
+ pyld = bfa_fcxp_get_reqbuf(fcxp);
+ bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+
+ len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port),
+ FDMI_RPRT);
+
+ attr_len = bfa_fcs_port_fdmi_build_rprt_pyld(fdmi,
+ (u8 *) ((struct ct_hdr_s *) pyld + 1));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len + attr_len, &fchs,
+ bfa_fcs_port_fdmi_rprt_response, (void *)fdmi,
+ FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT);
+}
+
+/**
+ * This routine builds Port Attribute Block that used in RPA, RPRT commands.
+ */
+static u16
+bfa_fcs_port_fdmi_build_portattr_block(struct bfa_fcs_port_fdmi_s *fdmi,
+ u8 *pyld)
+{
+ struct bfa_fcs_fdmi_port_attr_s fcs_port_attr;
+ struct fdmi_port_attr_s *port_attrib = (struct fdmi_port_attr_s *) pyld;
+ struct fdmi_attr_s *attr;
+ u8 *curr_ptr;
+ u16 len;
+ u8 count = 0;
+
+ /*
+ * get port attributes
+ */
+ bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr);
+
+ len = sizeof(port_attrib->attr_count);
+
+ /*
+ * fill out the invididual entries
+ */
+ curr_ptr = (u8 *) &port_attrib->port_attr;
+
+ /*
+ * FC4 Types
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FC4_TYPES);
+ attr->len = sizeof(fcs_port_attr.supp_fc4_types);
+ memcpy(attr->value, fcs_port_attr.supp_fc4_types, attr->len);
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * Supported Speed
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_SUPP_SPEED);
+ attr->len = sizeof(fcs_port_attr.supp_speed);
+ memcpy(attr->value, &fcs_port_attr.supp_speed, attr->len);
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * current Port Speed
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_PORT_SPEED);
+ attr->len = sizeof(fcs_port_attr.curr_speed);
+ memcpy(attr->value, &fcs_port_attr.curr_speed, attr->len);
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * max frame size
+ */
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_FRAME_SIZE);
+ attr->len = sizeof(fcs_port_attr.max_frm_size);
+ memcpy(attr->value, &fcs_port_attr.max_frm_size, attr->len);
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ /*
+ * OS Device Name
+ */
+ if (fcs_port_attr.os_device_name[0] != '\0') {
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_DEV_NAME);
+ attr->len = (u16) strlen(fcs_port_attr.os_device_name);
+ memcpy(attr->value, fcs_port_attr.os_device_name, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ }
+ /*
+ * Host Name
+ */
+ if (fcs_port_attr.host_name[0] != '\0') {
+ attr = (struct fdmi_attr_s *) curr_ptr;
+ attr->type = bfa_os_htons(FDMI_PORT_ATTRIB_HOST_NAME);
+ attr->len = (u16) strlen(fcs_port_attr.host_name);
+ memcpy(attr->value, fcs_port_attr.host_name, attr->len);
+ /* variable fields need to be 4 byte aligned */
+ attr->len = fc_roundup(attr->len, sizeof(u32));
+ curr_ptr += sizeof(attr->type) + sizeof(attr->len) + attr->len;
+ len += attr->len;
+ ++count;
+ attr->len =
+ bfa_os_htons(attr->len + sizeof(attr->type) +
+ sizeof(attr->len));
+
+ }
+
+ /*
+ * Update size of payload
+ */
+ port_attrib->attr_count = bfa_os_htonl(count);
+ len += ((sizeof(attr->type) + sizeof(attr->len)) * count);
+ return len;
+}
+
+static u16
+bfa_fcs_port_fdmi_build_rprt_pyld(struct bfa_fcs_port_fdmi_s *fdmi,
+ u8 *pyld)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct fdmi_rprt_s *rprt = (struct fdmi_rprt_s *) pyld;
+ u16 len;
+
+ rprt->hba_id = bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs));
+ rprt->port_name = bfa_fcs_port_get_pwwn(port);
+
+ len = bfa_fcs_port_fdmi_build_portattr_block(fdmi,
+ (u8 *) &rprt->port_attr_blk);
+
+ len += sizeof(rprt->hba_id) + sizeof(rprt->port_name);
+
+ return len;
+}
+
+static void
+bfa_fcs_port_fdmi_rprt_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_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg;
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct ct_hdr_s *cthdr = NULL;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
+ cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
+ return;
+ }
+
+ bfa_trc(port->fcs, cthdr->reason_code);
+ bfa_trc(port->fcs, cthdr->exp_code);
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
+}
+
+/**
+* RPA : Register Port Attributes.
+ */
+static void
+bfa_fcs_port_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = fdmi_cbarg;
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct fchs_s fchs;
+ u16 len, attr_len;
+ struct bfa_fcxp_s *fcxp;
+ u8 *pyld;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe,
+ bfa_fcs_port_fdmi_send_rpa, fdmi);
+ return;
+ }
+ fdmi->fcxp = fcxp;
+
+ pyld = bfa_fcxp_get_reqbuf(fcxp);
+ bfa_os_memset(pyld, 0, FC_MAX_PDUSZ);
+
+ len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_port_get_fcid(port),
+ FDMI_RPA);
+
+ attr_len = bfa_fcs_port_fdmi_build_rpa_pyld(fdmi,
+ (u8 *) ((struct ct_hdr_s *) pyld + 1));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len + attr_len, &fchs,
+ bfa_fcs_port_fdmi_rpa_response, (void *)fdmi,
+ FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RPA_SENT);
+}
+
+static u16
+bfa_fcs_port_fdmi_build_rpa_pyld(struct bfa_fcs_port_fdmi_s *fdmi,
+ u8 *pyld)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct fdmi_rpa_s *rpa = (struct fdmi_rpa_s *) pyld;
+ u16 len;
+
+ rpa->port_name = bfa_fcs_port_get_pwwn(port);
+
+ len = bfa_fcs_port_fdmi_build_portattr_block(fdmi,
+ (u8 *) &rpa->port_attr_blk);
+
+ len += sizeof(rpa->port_name);
+
+ return len;
+}
+
+static void
+bfa_fcs_port_fdmi_rpa_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_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)cbarg;
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct ct_hdr_s *cthdr = NULL;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
+ cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK);
+ return;
+ }
+
+ bfa_trc(port->fcs, cthdr->reason_code);
+ bfa_trc(port->fcs, cthdr->exp_code);
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR);
+}
+
+static void
+bfa_fcs_port_fdmi_timeout(void *arg)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = (struct bfa_fcs_port_fdmi_s *)arg;
+
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT);
+}
+
+static void
+bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_port_fdmi_s *fdmi,
+ struct bfa_fcs_fdmi_hba_attr_s *hba_attr)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info;
+ struct bfa_adapter_attr_s adapter_attr;
+
+ bfa_os_memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s));
+ bfa_os_memset(&adapter_attr, 0, sizeof(struct bfa_adapter_attr_s));
+
+ bfa_ioc_get_adapter_attr(&port->fcs->bfa->ioc, &adapter_attr);
+
+ strncpy(hba_attr->manufacturer, adapter_attr.manufacturer,
+ sizeof(adapter_attr.manufacturer));
+
+ strncpy(hba_attr->serial_num, adapter_attr.serial_num,
+ sizeof(adapter_attr.serial_num));
+
+ strncpy(hba_attr->model, adapter_attr.model, sizeof(hba_attr->model));
+
+ strncpy(hba_attr->model_desc, adapter_attr.model_descr,
+ sizeof(hba_attr->model_desc));
+
+ strncpy(hba_attr->hw_version, adapter_attr.hw_ver,
+ sizeof(hba_attr->hw_version));
+
+ strncpy(hba_attr->driver_version, (char *)driver_info->version,
+ sizeof(hba_attr->driver_version));
+
+ strncpy(hba_attr->option_rom_ver, adapter_attr.optrom_ver,
+ sizeof(hba_attr->option_rom_ver));
+
+ strncpy(hba_attr->fw_version, adapter_attr.fw_ver,
+ sizeof(hba_attr->fw_version));
+
+ strncpy(hba_attr->os_name, driver_info->host_os_name,
+ sizeof(hba_attr->os_name));
+
+ /*
+ * If there is a patch level, append it to the os name along with a
+ * separator
+ */
+ if (driver_info->host_os_patch[0] != '\0') {
+ strncat(hba_attr->os_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR,
+ sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR));
+ strncat(hba_attr->os_name, driver_info->host_os_patch,
+ sizeof(driver_info->host_os_patch));
+ }
+
+ hba_attr->max_ct_pyld = bfa_os_htonl(FC_MAX_PDUSZ);
+
+}
+
+static void
+bfa_fcs_fdmi_get_portattr(struct bfa_fcs_port_fdmi_s *fdmi,
+ struct bfa_fcs_fdmi_port_attr_s *port_attr)
+{
+ struct bfa_fcs_port_s *port = fdmi->ms->port;
+ struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info;
+ struct bfa_pport_attr_s pport_attr;
+
+ bfa_os_memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s));
+
+ /*
+ * get pport attributes from hal
+ */
+ bfa_pport_get_attr(port->fcs->bfa, &pport_attr);
+
+ /*
+ * get FC4 type Bitmask
+ */
+ fc_get_fc4type_bitmask(FC_TYPE_FCP, port_attr->supp_fc4_types);
+
+ /*
+ * Supported Speeds
+ */
+ port_attr->supp_speed = bfa_os_htonl(BFA_FCS_FDMI_SUPORTED_SPEEDS);
+
+ /*
+ * Current Speed
+ */
+ port_attr->curr_speed = bfa_os_htonl(pport_attr.speed);
+
+ /*
+ * Max PDU Size.
+ */
+ port_attr->max_frm_size = bfa_os_htonl(FC_MAX_PDUSZ);
+
+ /*
+ * OS device Name
+ */
+ strncpy(port_attr->os_device_name, (char *)driver_info->os_device_name,
+ sizeof(port_attr->os_device_name));
+
+ /*
+ * Host name
+ */
+ strncpy(port_attr->host_name, (char *)driver_info->host_machine_name,
+ sizeof(port_attr->host_name));
+
+}
+
+
+void
+bfa_fcs_port_fdmi_init(struct bfa_fcs_port_ms_s *ms)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi;
+
+ fdmi->ms = ms;
+ bfa_sm_set_state(fdmi, bfa_fcs_port_fdmi_sm_offline);
+}
+
+void
+bfa_fcs_port_fdmi_offline(struct bfa_fcs_port_ms_s *ms)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi;
+
+ fdmi->ms = ms;
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_OFFLINE);
+}
+
+void
+bfa_fcs_port_fdmi_online(struct bfa_fcs_port_ms_s *ms)
+{
+ struct bfa_fcs_port_fdmi_s *fdmi = &ms->fdmi;
+
+ fdmi->ms = ms;
+ bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_ONLINE);
+}
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen.h b/drivers/scsi/bfa/include/aen/bfa_aen.h
new file mode 100644
index 000000000000..d9cbc2a783d4
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_AEN_H__
+#define __BFA_AEN_H__
+
+#include "defs/bfa_defs_aen.h"
+
+#define BFA_AEN_MAX_ENTRY 512
+
+extern s32 bfa_aen_max_cfg_entry;
+struct bfa_aen_s {
+ void *bfad;
+ s32 max_entry;
+ s32 write_index;
+ s32 read_index;
+ u32 bfad_num;
+ u32 seq_num;
+ void (*aen_cb_notify)(void *bfad);
+ void (*gettimeofday)(struct bfa_timeval_s *tv);
+ struct bfa_trc_mod_s *trcmod;
+ struct bfa_aen_entry_s list[BFA_AEN_MAX_ENTRY]; /* Must be the last */
+};
+
+
+/**
+ * Public APIs
+ */
+static inline void
+bfa_aen_set_max_cfg_entry(int max_entry)
+{
+ bfa_aen_max_cfg_entry = max_entry;
+}
+
+static inline s32
+bfa_aen_get_max_cfg_entry(void)
+{
+ return bfa_aen_max_cfg_entry;
+}
+
+static inline s32
+bfa_aen_get_meminfo(void)
+{
+ return sizeof(struct bfa_aen_entry_s) * bfa_aen_get_max_cfg_entry();
+}
+
+static inline s32
+bfa_aen_get_wi(struct bfa_aen_s *aen)
+{
+ return aen->write_index;
+}
+
+static inline s32
+bfa_aen_get_ri(struct bfa_aen_s *aen)
+{
+ return aen->read_index;
+}
+
+static inline s32
+bfa_aen_fetch_count(struct bfa_aen_s *aen, s32 read_index)
+{
+ return ((aen->write_index + aen->max_entry) - read_index)
+ % aen->max_entry;
+}
+
+s32 bfa_aen_init(struct bfa_aen_s *aen, struct bfa_trc_mod_s *trcmod,
+ void *bfad, u32 inst_id, void (*aen_cb_notify)(void *),
+ void (*gettimeofday)(struct bfa_timeval_s *));
+
+s32 bfa_aen_post(struct bfa_aen_s *aen, enum bfa_aen_category aen_category,
+ int aen_type, union bfa_aen_data_u *aen_data);
+
+s32 bfa_aen_fetch(struct bfa_aen_s *aen, struct bfa_aen_entry_s *aen_entry,
+ s32 entry_space, s32 rii, s32 *ri_arr,
+ s32 ri_arr_cnt);
+
+s32 bfa_aen_get_inst(struct bfa_aen_s *aen);
+
+#endif /* __BFA_AEN_H__ */
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h b/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h
new file mode 100644
index 000000000000..260d3ea1cab3
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_adapter.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/* messages define for BFA_AEN_CAT_ADAPTER Module */
+#ifndef __bfa_aen_adapter_h__
+#define __bfa_aen_adapter_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_ADAPTER_ADD \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ADAPTER, BFA_ADAPTER_AEN_ADD)
+#define BFA_AEN_ADAPTER_REMOVE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ADAPTER, BFA_ADAPTER_AEN_REMOVE)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_audit.h b/drivers/scsi/bfa/include/aen/bfa_aen_audit.h
new file mode 100644
index 000000000000..12cd7aab5d53
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_audit.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/* messages define for BFA_AEN_CAT_AUDIT Module */
+#ifndef __bfa_aen_audit_h__
+#define __bfa_aen_audit_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_AUDIT_AUTH_ENABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_AUDIT, BFA_AUDIT_AEN_AUTH_ENABLE)
+#define BFA_AEN_AUDIT_AUTH_DISABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_AUDIT, BFA_AUDIT_AEN_AUTH_DISABLE)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h b/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h
new file mode 100644
index 000000000000..507d0b58d149
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_ethport.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/* messages define for BFA_AEN_CAT_ETHPORT Module */
+#ifndef __bfa_aen_ethport_h__
+#define __bfa_aen_ethport_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_ETHPORT_LINKUP \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_LINKUP)
+#define BFA_AEN_ETHPORT_LINKDOWN \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_LINKDOWN)
+#define BFA_AEN_ETHPORT_ENABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_ENABLE)
+#define BFA_AEN_ETHPORT_DISABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ETHPORT, BFA_ETHPORT_AEN_DISABLE)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h
new file mode 100644
index 000000000000..71378b446b69
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_ioc.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/* messages define for BFA_AEN_CAT_IOC Module */
+#ifndef __bfa_aen_ioc_h__
+#define __bfa_aen_ioc_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_IOC_HBGOOD \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_HBGOOD)
+#define BFA_AEN_IOC_HBFAIL \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_HBFAIL)
+#define BFA_AEN_IOC_ENABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_ENABLE)
+#define BFA_AEN_IOC_DISABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_DISABLE)
+#define BFA_AEN_IOC_FWMISMATCH \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_IOC, BFA_IOC_AEN_FWMISMATCH)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_itnim.h b/drivers/scsi/bfa/include/aen/bfa_aen_itnim.h
new file mode 100644
index 000000000000..a7d8ddcfef99
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_itnim.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/* messages define for BFA_AEN_CAT_ITNIM Module */
+#ifndef __bfa_aen_itnim_h__
+#define __bfa_aen_itnim_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_ITNIM_ONLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_ONLINE)
+#define BFA_AEN_ITNIM_OFFLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_OFFLINE)
+#define BFA_AEN_ITNIM_DISCONNECT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_ITNIM, BFA_ITNIM_AEN_DISCONNECT)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_lport.h b/drivers/scsi/bfa/include/aen/bfa_aen_lport.h
new file mode 100644
index 000000000000..5a8ebb65193f
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_lport.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/* messages define for BFA_AEN_CAT_LPORT Module */
+#ifndef __bfa_aen_lport_h__
+#define __bfa_aen_lport_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_LPORT_NEW \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW)
+#define BFA_AEN_LPORT_DELETE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE)
+#define BFA_AEN_LPORT_ONLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_ONLINE)
+#define BFA_AEN_LPORT_OFFLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_OFFLINE)
+#define BFA_AEN_LPORT_DISCONNECT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DISCONNECT)
+#define BFA_AEN_LPORT_NEW_PROP \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW_PROP)
+#define BFA_AEN_LPORT_DELETE_PROP \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE_PROP)
+#define BFA_AEN_LPORT_NEW_STANDARD \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NEW_STANDARD)
+#define BFA_AEN_LPORT_DELETE_STANDARD \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_DELETE_STANDARD)
+#define BFA_AEN_LPORT_NPIV_DUP_WWN \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_DUP_WWN)
+#define BFA_AEN_LPORT_NPIV_FABRIC_MAX \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_FABRIC_MAX)
+#define BFA_AEN_LPORT_NPIV_UNKNOWN \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_LPORT, BFA_LPORT_AEN_NPIV_UNKNOWN)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_port.h b/drivers/scsi/bfa/include/aen/bfa_aen_port.h
new file mode 100644
index 000000000000..9add905a622d
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_port.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/* messages define for BFA_AEN_CAT_PORT Module */
+#ifndef __bfa_aen_port_h__
+#define __bfa_aen_port_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_PORT_ONLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_ONLINE)
+#define BFA_AEN_PORT_OFFLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_OFFLINE)
+#define BFA_AEN_PORT_RLIR \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_RLIR)
+#define BFA_AEN_PORT_SFP_INSERT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_INSERT)
+#define BFA_AEN_PORT_SFP_REMOVE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_REMOVE)
+#define BFA_AEN_PORT_SFP_POM \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_POM)
+#define BFA_AEN_PORT_ENABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_ENABLE)
+#define BFA_AEN_PORT_DISABLE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_DISABLE)
+#define BFA_AEN_PORT_AUTH_ON \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_AUTH_ON)
+#define BFA_AEN_PORT_AUTH_OFF \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_AUTH_OFF)
+#define BFA_AEN_PORT_DISCONNECT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_DISCONNECT)
+#define BFA_AEN_PORT_QOS_NEG \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_QOS_NEG)
+#define BFA_AEN_PORT_FABRIC_NAME_CHANGE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_FABRIC_NAME_CHANGE)
+#define BFA_AEN_PORT_SFP_ACCESS_ERROR \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_ACCESS_ERROR)
+#define BFA_AEN_PORT_SFP_UNSUPPORT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_PORT, BFA_PORT_AEN_SFP_UNSUPPORT)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/aen/bfa_aen_rport.h b/drivers/scsi/bfa/include/aen/bfa_aen_rport.h
new file mode 100644
index 000000000000..7e4be1fd5e15
--- /dev/null
+++ b/drivers/scsi/bfa/include/aen/bfa_aen_rport.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/* messages define for BFA_AEN_CAT_RPORT Module */
+#ifndef __bfa_aen_rport_h__
+#define __bfa_aen_rport_h__
+
+#include <cs/bfa_log.h>
+#include <defs/bfa_defs_aen.h>
+
+#define BFA_AEN_RPORT_ONLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_ONLINE)
+#define BFA_AEN_RPORT_OFFLINE \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_OFFLINE)
+#define BFA_AEN_RPORT_DISCONNECT \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_DISCONNECT)
+#define BFA_AEN_RPORT_QOS_PRIO \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_QOS_PRIO)
+#define BFA_AEN_RPORT_QOS_FLOWID \
+ BFA_LOG_CREATE_ID(BFA_AEN_CAT_RPORT, BFA_RPORT_AEN_QOS_FLOWID)
+
+#endif
+
diff --git a/drivers/scsi/bfa/include/bfa.h b/drivers/scsi/bfa/include/bfa.h
new file mode 100644
index 000000000000..d4bc0d9fa42c
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfa.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_H__
+#define __BFA_H__
+
+#include <bfa_os_inc.h>
+#include <cs/bfa_debug.h>
+#include <cs/bfa_q.h>
+#include <cs/bfa_trc.h>
+#include <cs/bfa_log.h>
+#include <cs/bfa_plog.h>
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_ioc.h>
+#include <defs/bfa_defs_iocfc.h>
+#include <aen/bfa_aen.h>
+#include <bfi/bfi.h>
+
+struct bfa_s;
+#include <bfa_intr_priv.h>
+
+struct bfa_pcidev_s;
+
+/**
+ * PCI devices supported by the current BFA
+ */
+struct bfa_pciid_s {
+ u16 device_id;
+ u16 vendor_id;
+};
+
+extern char bfa_version[];
+
+/**
+ * BFA Power Mgmt Commands
+ */
+enum bfa_pm_cmd {
+ BFA_PM_CTL_D0 = 0,
+ BFA_PM_CTL_D1 = 1,
+ BFA_PM_CTL_D2 = 2,
+ BFA_PM_CTL_D3 = 3,
+};
+
+/**
+ * BFA memory resources
+ */
+enum bfa_mem_type {
+ BFA_MEM_TYPE_KVA = 1, /*! Kernel Virtual Memory *(non-dma-able) */
+ BFA_MEM_TYPE_DMA = 2, /*! DMA-able memory */
+ BFA_MEM_TYPE_MAX = BFA_MEM_TYPE_DMA,
+};
+
+struct bfa_mem_elem_s {
+ enum bfa_mem_type mem_type; /* see enum bfa_mem_type */
+ u32 mem_len; /* Total Length in Bytes */
+ u8 *kva; /* kernel virtual address */
+ u64 dma; /* dma address if DMA memory */
+ u8 *kva_curp; /* kva allocation cursor */
+ u64 dma_curp; /* dma allocation cursor */
+};
+
+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)
+#define bfa_meminfo_dma_virt(_m) \
+ ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].kva_curp)
+#define bfa_meminfo_dma_phys(_m) \
+ ((_m)->meminfo[BFA_MEM_TYPE_DMA - 1].dma_curp)
+
+/**
+ * Generic Scatter Gather Element used by driver
+ */
+struct bfa_sge_s {
+ u32 sg_len;
+ void *sg_addr;
+};
+
+#define bfa_sge_to_be(__sge) do { \
+ ((u32 *)(__sge))[0] = bfa_os_htonl(((u32 *)(__sge))[0]); \
+ ((u32 *)(__sge))[1] = bfa_os_htonl(((u32 *)(__sge))[1]); \
+ ((u32 *)(__sge))[2] = bfa_os_htonl(((u32 *)(__sge))[2]); \
+} while (0)
+
+
+/*
+ * bfa stats interfaces
+ */
+#define bfa_stats(_mod, _stats) ((_mod)->stats._stats++)
+
+#define bfa_ioc_get_stats(__bfa, __ioc_stats) \
+ bfa_ioc_fetch_stats(&(__bfa)->ioc, __ioc_stats)
+#define bfa_ioc_clear_stats(__bfa) \
+ bfa_ioc_clr_stats(&(__bfa)->ioc)
+
+/*
+ * bfa API functions
+ */
+void bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids);
+void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg);
+void bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg);
+void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo);
+void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg,
+ struct bfa_meminfo_s *meminfo,
+ struct bfa_pcidev_s *pcidev);
+void bfa_init_trc(struct bfa_s *bfa, struct bfa_trc_mod_s *trcmod);
+void bfa_init_log(struct bfa_s *bfa, struct bfa_log_mod_s *logmod);
+void bfa_init_aen(struct bfa_s *bfa, struct bfa_aen_s *aen);
+void bfa_init_plog(struct bfa_s *bfa, struct bfa_plog_s *plog);
+void bfa_detach(struct bfa_s *bfa);
+void bfa_init(struct bfa_s *bfa);
+void bfa_start(struct bfa_s *bfa);
+void bfa_stop(struct bfa_s *bfa);
+void bfa_attach_fcs(struct bfa_s *bfa);
+void bfa_cb_init(void *bfad, bfa_status_t status);
+void bfa_cb_stop(void *bfad, bfa_status_t status);
+void bfa_cb_updateq(void *bfad, bfa_status_t status);
+
+bfa_boolean_t bfa_intx(struct bfa_s *bfa);
+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))
+
+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);
+void bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q);
+
+typedef void (*bfa_cb_ioc_t) (void *cbarg, enum bfa_status status);
+void bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr);
+bfa_status_t bfa_iocfc_get_stats(struct bfa_s *bfa,
+ struct bfa_iocfc_stats_s *stats,
+ bfa_cb_ioc_t cbfn, void *cbarg);
+bfa_status_t bfa_iocfc_clear_stats(struct bfa_s *bfa,
+ bfa_cb_ioc_t cbfn, void *cbarg);
+void bfa_get_attr(struct bfa_s *bfa, struct bfa_ioc_attr_s *ioc_attr);
+
+void bfa_adapter_get_attr(struct bfa_s *bfa,
+ struct bfa_adapter_attr_s *ad_attr);
+u64 bfa_adapter_get_id(struct bfa_s *bfa);
+
+bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa,
+ struct bfa_iocfc_intr_attr_s *attr);
+
+void bfa_iocfc_enable(struct bfa_s *bfa);
+void bfa_iocfc_disable(struct bfa_s *bfa);
+void bfa_ioc_auto_recover(bfa_boolean_t auto_recover);
+void bfa_cb_ioc_disable(void *bfad);
+void bfa_timer_tick(struct bfa_s *bfa);
+#define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout) \
+ bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout)
+
+/*
+ * BFA debug API functions
+ */
+bfa_status_t bfa_debug_fwtrc(struct bfa_s *bfa, void *trcdata, int *trclen);
+bfa_status_t bfa_debug_fwsave(struct bfa_s *bfa, void *trcdata, int *trclen);
+
+#include "bfa_priv.h"
+
+#endif /* __BFA_H__ */
diff --git a/drivers/scsi/bfa/include/bfa_fcpim.h b/drivers/scsi/bfa/include/bfa_fcpim.h
new file mode 100644
index 000000000000..04789795fa53
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfa_fcpim.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_FCPIM_H__
+#define __BFA_FCPIM_H__
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_fcpim.h>
+#include <defs/bfa_defs_fcpim.h>
+
+/*
+ * forward declarations
+ */
+struct bfa_itnim_s;
+struct bfa_ioim_s;
+struct bfa_tskim_s;
+struct bfad_ioim_s;
+struct bfad_tskim_s;
+
+/*
+ * bfa fcpim module API functions
+ */
+void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov);
+u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa);
+void bfa_fcpim_qdepth_set(struct bfa_s *bfa, u16 q_depth);
+u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa);
+bfa_status_t bfa_fcpim_get_modstats(struct bfa_s *bfa,
+ struct bfa_fcpim_stats_s *modstats);
+bfa_status_t bfa_fcpim_clr_modstats(struct bfa_s *bfa);
+
+/*
+ * bfa itnim API functions
+ */
+struct bfa_itnim_s *bfa_itnim_create(struct bfa_s *bfa,
+ struct bfa_rport_s *rport, void *itnim);
+void bfa_itnim_delete(struct bfa_itnim_s *itnim);
+void bfa_itnim_online(struct bfa_itnim_s *itnim,
+ bfa_boolean_t seq_rec);
+void bfa_itnim_offline(struct bfa_itnim_s *itnim);
+void bfa_itnim_get_stats(struct bfa_itnim_s *itnim,
+ struct bfa_itnim_hal_stats_s *stats);
+void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim);
+
+
+/**
+ * BFA completion callback for bfa_itnim_online().
+ *
+ * @param[in] itnim FCS or driver itnim instance
+ *
+ * return None
+ */
+void bfa_cb_itnim_online(void *itnim);
+
+/**
+ * BFA completion callback for bfa_itnim_offline().
+ *
+ * @param[in] itnim FCS or driver itnim instance
+ *
+ * return None
+ */
+void bfa_cb_itnim_offline(void *itnim);
+void bfa_cb_itnim_tov_begin(void *itnim);
+void bfa_cb_itnim_tov(void *itnim);
+
+/**
+ * BFA notification to FCS/driver for second level error recovery.
+ *
+ * Atleast one I/O request has timedout and target is unresponsive to
+ * repeated abort requests. Second level error recovery should be initiated
+ * by starting implicit logout and recovery procedures.
+ *
+ * @param[in] itnim FCS or driver itnim instance
+ *
+ * return None
+ */
+void bfa_cb_itnim_sler(void *itnim);
+
+/*
+ * bfa ioim API functions
+ */
+struct bfa_ioim_s *bfa_ioim_alloc(struct bfa_s *bfa,
+ struct bfad_ioim_s *dio,
+ struct bfa_itnim_s *itnim,
+ u16 nsgles);
+
+void bfa_ioim_free(struct bfa_ioim_s *ioim);
+void bfa_ioim_start(struct bfa_ioim_s *ioim);
+void bfa_ioim_abort(struct bfa_ioim_s *ioim);
+void bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim,
+ bfa_boolean_t iotov);
+
+
+/**
+ * I/O completion notification.
+ *
+ * @param[in] dio driver IO structure
+ * @param[in] io_status IO completion status
+ * @param[in] scsi_status SCSI status returned by target
+ * @param[in] sns_len SCSI sense length, 0 if none
+ * @param[in] sns_info SCSI sense data, if any
+ * @param[in] residue Residual length
+ *
+ * @return None
+ */
+void bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio,
+ enum bfi_ioim_status io_status,
+ u8 scsi_status, int sns_len,
+ u8 *sns_info, s32 residue);
+
+/**
+ * I/O good completion notification.
+ *
+ * @param[in] dio driver IO structure
+ *
+ * @return None
+ */
+void bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio);
+
+/**
+ * I/O abort completion notification
+ *
+ * @param[in] dio driver IO that was aborted
+ *
+ * @return None
+ */
+void bfa_cb_ioim_abort(void *bfad, struct bfad_ioim_s *dio);
+void bfa_cb_ioim_resfree(void *hcb_bfad);
+
+void bfa_cb_ioim_resfree(void *hcb_bfad);
+
+/*
+ * bfa tskim API functions
+ */
+struct bfa_tskim_s *bfa_tskim_alloc(struct bfa_s *bfa,
+ struct bfad_tskim_s *dtsk);
+void bfa_tskim_free(struct bfa_tskim_s *tskim);
+void bfa_tskim_start(struct bfa_tskim_s *tskim,
+ struct bfa_itnim_s *itnim, lun_t lun,
+ enum fcp_tm_cmnd tm, u8 t_secs);
+void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk,
+ enum bfi_tskim_status tsk_status);
+
+#endif /* __BFA_FCPIM_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfa_fcptm.h b/drivers/scsi/bfa/include/bfa_fcptm.h
new file mode 100644
index 000000000000..5f5ffe0bb1bb
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfa_fcptm.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_FCPTM_H__
+#define __BFA_FCPTM_H__
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <bfi/bfi_fcptm.h>
+
+/*
+ * forward declarations
+ */
+struct bfa_tin_s;
+struct bfa_iotm_s;
+struct bfa_tsktm_s;
+
+/*
+ * bfa fcptm module API functions
+ */
+void bfa_fcptm_path_tov_set(struct bfa_s *bfa, u16 path_tov);
+u16 bfa_fcptm_path_tov_get(struct bfa_s *bfa);
+void bfa_fcptm_qdepth_set(struct bfa_s *bfa, u16 q_depth);
+u16 bfa_fcptm_qdepth_get(struct bfa_s *bfa);
+
+/*
+ * bfa tin API functions
+ */
+void bfa_tin_get_stats(struct bfa_tin_s *tin, struct bfa_tin_stats_s *stats);
+void bfa_tin_clear_stats(struct bfa_tin_s *tin);
+
+#endif /* __BFA_FCPTM_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfa_svc.h b/drivers/scsi/bfa/include/bfa_svc.h
new file mode 100644
index 000000000000..268d956bad89
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfa_svc.h
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_SVC_H__
+#define __BFA_SVC_H__
+
+/*
+ * forward declarations
+ */
+struct bfa_fcxp_s;
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_pport.h>
+#include <defs/bfa_defs_rport.h>
+#include <defs/bfa_defs_qos.h>
+#include <cs/bfa_sm.h>
+#include <bfa.h>
+
+/**
+ * BFA rport information.
+ */
+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 */
+ u8 fc_class; /* supported FC classes. enum fc_cos */
+ u8 vf_en; /* virtual fabric enable */
+ u16 vf_id; /* virtual fabric ID */
+ enum bfa_pport_speed speed; /* Rport's current speed */
+};
+
+/**
+ * BFA rport data structure
+ */
+struct bfa_rport_s {
+ struct list_head qe; /* queue element */
+ bfa_sm_t sm; /* state machine */
+ struct bfa_s *bfa; /* backpointer to BFA */
+ void *rport_drv; /* fcs/driver rport object */
+ u16 fw_handle; /* firmware rport handle */
+ u16 rport_tag; /* BFA rport tag */
+ struct bfa_rport_info_s rport_info; /* rport info from *fcs/driver */
+ struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */
+ struct bfa_cb_qe_s hcb_qe; /* BFA callback qelem */
+ struct bfa_rport_hal_stats_s stats; /* BFA rport statistics */
+ struct bfa_rport_qos_attr_s qos_attr;
+ union a {
+ bfa_status_t status; /* f/w status */
+ void *fw_msg; /* QoS scn event */
+ } event_arg;
+};
+#define BFA_RPORT_FC_COS(_rport) ((_rport)->rport_info.fc_class)
+
+/**
+ * Send completion callback.
+ */
+typedef void (*bfa_cb_fcxp_send_t) (void *bfad_fcxp, struct bfa_fcxp_s *fcxp,
+ void *cbarg, enum bfa_status req_status,
+ u32 rsp_len, u32 resid_len,
+ struct fchs_s *rsp_fchs);
+
+/**
+ * BFA fcxp allocation (asynchronous)
+ */
+typedef void (*bfa_fcxp_alloc_cbfn_t) (void *cbarg, struct bfa_fcxp_s *fcxp);
+
+struct bfa_fcxp_wqe_s {
+ struct list_head qe;
+ bfa_fcxp_alloc_cbfn_t alloc_cbfn;
+ void *alloc_cbarg;
+};
+
+typedef u64 (*bfa_fcxp_get_sgaddr_t) (void *bfad_fcxp, int sgeid);
+typedef u32 (*bfa_fcxp_get_sglen_t) (void *bfad_fcxp, int sgeid);
+
+#define BFA_UF_BUFSZ (2 * 1024 + 256)
+
+/**
+ * @todo private
+ */
+struct bfa_uf_buf_s {
+ u8 d[BFA_UF_BUFSZ];
+};
+
+
+struct bfa_uf_s {
+ struct list_head qe; /* queue element */
+ struct bfa_s *bfa; /* bfa instance */
+ u16 uf_tag; /* identifying tag f/w messages */
+ u16 vf_id;
+ u16 src_rport_handle;
+ u16 rsvd;
+ u8 *data_ptr;
+ u16 data_len; /* actual receive length */
+ u16 pb_len; /* posted buffer length */
+ void *buf_kva; /* buffer virtual address */
+ u64 buf_pa; /* buffer physical address */
+ struct bfa_cb_qe_s hcb_qe; /* comp: BFA comp qelem */
+ struct bfa_sge_s sges[BFI_SGE_INLINE_MAX];
+};
+
+typedef void (*bfa_cb_pport_t) (void *cbarg, enum bfa_status status);
+
+/**
+ * bfa lport login/logout service interface
+ */
+struct bfa_lps_s {
+ struct list_head qe; /* queue element */
+ struct bfa_s *bfa; /* parent bfa instance */
+ bfa_sm_t sm; /* finite state machine */
+ u8 lp_tag; /* lport tag */
+ u8 reqq; /* lport request queue */
+ u8 alpa; /* ALPA for loop topologies */
+ u32 lp_pid; /* lport port ID */
+ bfa_boolean_t fdisc; /* send FDISC instead of FLOGI*/
+ bfa_boolean_t auth_en; /* enable authentication */
+ bfa_boolean_t auth_req; /* authentication required */
+ bfa_boolean_t npiv_en; /* NPIV is allowed by peer */
+ bfa_boolean_t fport; /* attached peer is F_PORT */
+ bfa_boolean_t brcd_switch;/* attached peer is brcd switch */
+ bfa_status_t status; /* login status */
+ u16 pdusz; /* max receive PDU size */
+ u16 pr_bbcred; /* BB_CREDIT from peer */
+ u8 lsrjt_rsn; /* LSRJT reason */
+ u8 lsrjt_expl; /* LSRJT explanation */
+ wwn_t pwwn; /* port wwn of lport */
+ wwn_t nwwn; /* node wwn of lport */
+ wwn_t pr_pwwn; /* port wwn of lport peer */
+ wwn_t pr_nwwn; /* node wwn of lport peer */
+ mac_t lp_mac; /* fpma/spma MAC for lport */
+ mac_t fcf_mac; /* FCF MAC of lport */
+ struct bfa_reqq_wait_s wqe; /* request wait queue element */
+ void *uarg; /* user callback arg */
+ struct bfa_cb_qe_s hcb_qe; /* comp: callback qelem */
+ struct bfi_lps_login_rsp_s *loginrsp;
+ bfa_eproto_status_t ext_status;
+};
+
+/*
+ * bfa pport API functions
+ */
+bfa_status_t bfa_pport_enable(struct bfa_s *bfa);
+bfa_status_t bfa_pport_disable(struct bfa_s *bfa);
+bfa_status_t bfa_pport_cfg_speed(struct bfa_s *bfa,
+ enum bfa_pport_speed speed);
+enum bfa_pport_speed bfa_pport_get_speed(struct bfa_s *bfa);
+bfa_status_t bfa_pport_cfg_topology(struct bfa_s *bfa,
+ enum bfa_pport_topology topo);
+enum bfa_pport_topology bfa_pport_get_topology(struct bfa_s *bfa);
+bfa_status_t bfa_pport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa);
+bfa_boolean_t bfa_pport_get_hardalpa(struct bfa_s *bfa, u8 *alpa);
+u8 bfa_pport_get_myalpa(struct bfa_s *bfa);
+bfa_status_t bfa_pport_clr_hardalpa(struct bfa_s *bfa);
+bfa_status_t bfa_pport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxsize);
+u16 bfa_pport_get_maxfrsize(struct bfa_s *bfa);
+u32 bfa_pport_mypid(struct bfa_s *bfa);
+u8 bfa_pport_get_rx_bbcredit(struct bfa_s *bfa);
+bfa_status_t bfa_pport_trunk_enable(struct bfa_s *bfa, u8 bitmap);
+bfa_status_t bfa_pport_trunk_disable(struct bfa_s *bfa);
+bfa_boolean_t bfa_pport_trunk_query(struct bfa_s *bfa, u32 *bitmap);
+void bfa_pport_get_attr(struct bfa_s *bfa, struct bfa_pport_attr_s *attr);
+wwn_t bfa_pport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node);
+bfa_status_t bfa_pport_get_stats(struct bfa_s *bfa,
+ union bfa_pport_stats_u *stats,
+ bfa_cb_pport_t cbfn, void *cbarg);
+bfa_status_t bfa_pport_clear_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn,
+ void *cbarg);
+void bfa_pport_event_register(struct bfa_s *bfa,
+ void (*event_cbfn) (void *cbarg,
+ bfa_pport_event_t event), void *event_cbarg);
+bfa_boolean_t bfa_pport_is_disabled(struct bfa_s *bfa);
+void bfa_pport_cfg_qos(struct bfa_s *bfa, bfa_boolean_t on_off);
+void bfa_pport_cfg_ratelim(struct bfa_s *bfa, bfa_boolean_t on_off);
+bfa_status_t bfa_pport_cfg_ratelim_speed(struct bfa_s *bfa,
+ enum bfa_pport_speed speed);
+enum bfa_pport_speed bfa_pport_get_ratelim_speed(struct bfa_s *bfa);
+
+void bfa_pport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit);
+void bfa_pport_busy(struct bfa_s *bfa, bfa_boolean_t status);
+void bfa_pport_beacon(struct bfa_s *bfa, bfa_boolean_t beacon,
+ bfa_boolean_t link_e2e_beacon);
+void bfa_cb_pport_event(void *cbarg, bfa_pport_event_t event);
+void bfa_pport_qos_get_attr(struct bfa_s *bfa, struct bfa_qos_attr_s *qos_attr);
+void bfa_pport_qos_get_vc_attr(struct bfa_s *bfa,
+ struct bfa_qos_vc_attr_s *qos_vc_attr);
+bfa_status_t bfa_pport_get_qos_stats(struct bfa_s *bfa,
+ union bfa_pport_stats_u *stats,
+ bfa_cb_pport_t cbfn, void *cbarg);
+bfa_status_t bfa_pport_clear_qos_stats(struct bfa_s *bfa, bfa_cb_pport_t cbfn,
+ void *cbarg);
+bfa_boolean_t bfa_pport_is_ratelim(struct bfa_s *bfa);
+bfa_boolean_t bfa_pport_is_linkup(struct bfa_s *bfa);
+
+/*
+ * bfa rport API functions
+ */
+struct bfa_rport_s *bfa_rport_create(struct bfa_s *bfa, void *rport_drv);
+void bfa_rport_delete(struct bfa_rport_s *rport);
+void bfa_rport_online(struct bfa_rport_s *rport,
+ struct bfa_rport_info_s *rport_info);
+void bfa_rport_offline(struct bfa_rport_s *rport);
+void bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_pport_speed speed);
+void bfa_rport_get_stats(struct bfa_rport_s *rport,
+ struct bfa_rport_hal_stats_s *stats);
+void bfa_rport_clear_stats(struct bfa_rport_s *rport);
+void bfa_cb_rport_online(void *rport);
+void bfa_cb_rport_offline(void *rport);
+void bfa_cb_rport_qos_scn_flowid(void *rport,
+ struct bfa_rport_qos_attr_s old_qos_attr,
+ struct bfa_rport_qos_attr_s new_qos_attr);
+void bfa_cb_rport_qos_scn_prio(void *rport,
+ struct bfa_rport_qos_attr_s old_qos_attr,
+ struct bfa_rport_qos_attr_s new_qos_attr);
+void bfa_rport_get_qos_attr(struct bfa_rport_s *rport,
+ struct bfa_rport_qos_attr_s *qos_attr);
+
+/*
+ * bfa fcxp API functions
+ */
+struct bfa_fcxp_s *bfa_fcxp_alloc(void *bfad_fcxp, struct bfa_s *bfa,
+ int nreq_sgles, int nrsp_sgles,
+ bfa_fcxp_get_sgaddr_t get_req_sga,
+ bfa_fcxp_get_sglen_t get_req_sglen,
+ bfa_fcxp_get_sgaddr_t get_rsp_sga,
+ bfa_fcxp_get_sglen_t get_rsp_sglen);
+void bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe,
+ bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *cbarg);
+void bfa_fcxp_walloc_cancel(struct bfa_s *bfa,
+ struct bfa_fcxp_wqe_s *wqe);
+void bfa_fcxp_discard(struct bfa_fcxp_s *fcxp);
+
+void *bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp);
+void *bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp);
+
+void bfa_fcxp_free(struct bfa_fcxp_s *fcxp);
+
+void bfa_fcxp_send(struct bfa_fcxp_s *fcxp,
+ struct bfa_rport_s *rport, u16 vf_id, u8 lp_tag,
+ bfa_boolean_t cts, enum fc_cos cos,
+ u32 reqlen, struct fchs_s *fchs,
+ bfa_cb_fcxp_send_t cbfn,
+ void *cbarg,
+ u32 rsp_maxlen, u8 rsp_timeout);
+bfa_status_t bfa_fcxp_abort(struct bfa_fcxp_s *fcxp);
+u32 bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp);
+u32 bfa_fcxp_get_maxrsp(struct bfa_s *bfa);
+
+static inline void *
+bfa_uf_get_frmbuf(struct bfa_uf_s *uf)
+{
+ return uf->data_ptr;
+}
+
+static inline u16
+bfa_uf_get_frmlen(struct bfa_uf_s *uf)
+{
+ return uf->data_len;
+}
+
+/**
+ * Callback prototype for unsolicited frame receive handler.
+ *
+ * @param[in] cbarg callback arg for receive handler
+ * @param[in] uf unsolicited frame descriptor
+ *
+ * @return None
+ */
+typedef void (*bfa_cb_uf_recv_t) (void *cbarg, struct bfa_uf_s *uf);
+
+/*
+ * bfa uf API functions
+ */
+void bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv,
+ void *cbarg);
+void bfa_uf_free(struct bfa_uf_s *uf);
+
+/**
+ * bfa lport service api
+ */
+
+struct bfa_lps_s *bfa_lps_alloc(struct bfa_s *bfa);
+void bfa_lps_delete(struct bfa_lps_s *lps);
+void bfa_lps_discard(struct bfa_lps_s *lps);
+void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz,
+ wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en);
+void bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn,
+ wwn_t nwwn);
+void bfa_lps_flogo(struct bfa_lps_s *lps);
+void bfa_lps_fdisclogo(struct bfa_lps_s *lps);
+u8 bfa_lps_get_tag(struct bfa_lps_s *lps);
+bfa_boolean_t bfa_lps_is_npiv_en(struct bfa_lps_s *lps);
+bfa_boolean_t bfa_lps_is_fport(struct bfa_lps_s *lps);
+bfa_boolean_t bfa_lps_is_brcd_fabric(struct bfa_lps_s *lps);
+bfa_boolean_t bfa_lps_is_authreq(struct bfa_lps_s *lps);
+bfa_eproto_status_t bfa_lps_get_extstatus(struct bfa_lps_s *lps);
+u32 bfa_lps_get_pid(struct bfa_lps_s *lps);
+u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid);
+u16 bfa_lps_get_peer_bbcredit(struct bfa_lps_s *lps);
+wwn_t bfa_lps_get_peer_pwwn(struct bfa_lps_s *lps);
+wwn_t bfa_lps_get_peer_nwwn(struct bfa_lps_s *lps);
+u8 bfa_lps_get_lsrjt_rsn(struct bfa_lps_s *lps);
+u8 bfa_lps_get_lsrjt_expl(struct bfa_lps_s *lps);
+void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status);
+void bfa_cb_lps_flogo_comp(void *bfad, void *uarg);
+void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status);
+void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg);
+
+#endif /* __BFA_SVC_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfa_timer.h b/drivers/scsi/bfa/include/bfa_timer.h
new file mode 100644
index 000000000000..e407103fa565
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfa_timer.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_TIMER_H__
+#define __BFA_TIMER_H__
+
+#include <bfa_os_inc.h>
+#include <cs/bfa_q.h>
+
+struct bfa_s;
+
+typedef void (*bfa_timer_cbfn_t)(void *);
+
+/**
+ * BFA timer data structure
+ */
+struct bfa_timer_s {
+ struct list_head qe;
+ bfa_timer_cbfn_t timercb;
+ void *arg;
+ int timeout; /**< in millisecs. */
+};
+
+/**
+ * Timer module structure
+ */
+struct bfa_timer_mod_s {
+ struct list_head timer_q;
+};
+
+#define BFA_TIMER_FREQ 500 /**< specified in millisecs */
+
+void bfa_timer_beat(struct bfa_timer_mod_s *mod);
+void bfa_timer_init(struct bfa_timer_mod_s *mod);
+void bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
+ bfa_timer_cbfn_t timercb, void *arg,
+ unsigned int timeout);
+void bfa_timer_stop(struct bfa_timer_s *timer);
+
+#endif /* __BFA_TIMER_H__ */
diff --git a/drivers/scsi/bfa/include/bfi/bfi.h b/drivers/scsi/bfa/include/bfi/bfi.h
new file mode 100644
index 000000000000..7042c18e542d
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi.h
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFI_H__
+#define __BFI_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_status.h>
+
+#pragma pack(1)
+
+/**
+ * Msg header common to all msgs
+ */
+struct bfi_mhdr_s {
+ u8 msg_class; /* @ref bfi_mclass_t */
+ u8 msg_id; /* msg opcode with in the class */
+ union {
+ struct {
+ u8 rsvd;
+ u8 lpu_id; /* msg destination */
+ } h2i;
+ u16 i2htok; /* token in msgs to host */
+ } mtag;
+};
+
+#define bfi_h2i_set(_mh, _mc, _op, _lpuid) do { \
+ (_mh).msg_class = (_mc); \
+ (_mh).msg_id = (_op); \
+ (_mh).mtag.h2i.lpu_id = (_lpuid); \
+} while (0)
+
+#define bfi_i2h_set(_mh, _mc, _op, _i2htok) do { \
+ (_mh).msg_class = (_mc); \
+ (_mh).msg_id = (_op); \
+ (_mh).mtag.i2htok = (_i2htok); \
+} while (0)
+
+/*
+ * Message opcodes: 0-127 to firmware, 128-255 to host
+ */
+#define BFI_I2H_OPCODE_BASE 128
+#define BFA_I2HM(_x) ((_x) + BFI_I2H_OPCODE_BASE)
+
+/**
+ ****************************************************************************
+ *
+ * Scatter Gather Element and Page definition
+ *
+ ****************************************************************************
+ */
+
+#define BFI_SGE_INLINE 1
+#define BFI_SGE_INLINE_MAX (BFI_SGE_INLINE + 1)
+
+/**
+ * SG Flags
+ */
+enum {
+ BFI_SGE_DATA = 0, /* data address, not last */
+ BFI_SGE_DATA_CPL = 1, /* data addr, last in current page */
+ BFI_SGE_DATA_LAST = 3, /* data address, last */
+ BFI_SGE_LINK = 2, /* link address */
+ BFI_SGE_PGDLEN = 2, /* cumulative data length for page */
+};
+
+/**
+ * DMA addresses
+ */
+union bfi_addr_u {
+ struct {
+ u32 addr_lo;
+ u32 addr_hi;
+ } a32;
+};
+
+/**
+ * Scatter Gather Element
+ */
+struct bfi_sge_s {
+#ifdef __BIGENDIAN
+ u32 flags:2,
+ rsvd:2,
+ sg_len:28;
+#else
+ u32 sg_len:28,
+ rsvd:2,
+ flags:2;
+#endif
+ union bfi_addr_u sga;
+};
+
+/**
+ * Scatter Gather Page
+ */
+#define BFI_SGPG_DATA_SGES 7
+#define BFI_SGPG_SGES_MAX (BFI_SGPG_DATA_SGES + 1)
+#define BFI_SGPG_RSVD_WD_LEN 8
+struct bfi_sgpg_s {
+ struct bfi_sge_s sges[BFI_SGPG_SGES_MAX];
+ u32 rsvd[BFI_SGPG_RSVD_WD_LEN];
+};
+
+/*
+ * Large Message structure - 128 Bytes size Msgs
+ */
+#define BFI_LMSG_SZ 128
+#define BFI_LMSG_PL_WSZ \
+ ((BFI_LMSG_SZ - sizeof(struct bfi_mhdr_s)) / 4)
+
+struct bfi_msg_s {
+ struct bfi_mhdr_s mhdr;
+ u32 pl[BFI_LMSG_PL_WSZ];
+};
+
+/**
+ * Mailbox message structure
+ */
+#define BFI_MBMSG_SZ 7
+struct bfi_mbmsg_s {
+ struct bfi_mhdr_s mh;
+ u32 pl[BFI_MBMSG_SZ];
+};
+
+/**
+ * Message Classes
+ */
+enum bfi_mclass {
+ BFI_MC_IOC = 1, /* IO Controller (IOC) */
+ BFI_MC_DIAG = 2, /* Diagnostic Msgs */
+ BFI_MC_FLASH = 3, /* Flash message class */
+ BFI_MC_CEE = 4,
+ BFI_MC_FC_PORT = 5, /* FC port */
+ BFI_MC_IOCFC = 6, /* FC - IO Controller (IOC) */
+ BFI_MC_LL = 7, /* Link Layer */
+ BFI_MC_UF = 8, /* Unsolicited frame receive */
+ BFI_MC_FCXP = 9, /* FC Transport */
+ BFI_MC_LPS = 10, /* lport fc login services */
+ BFI_MC_RPORT = 11, /* Remote port */
+ BFI_MC_ITNIM = 12, /* I-T nexus (Initiator mode) */
+ BFI_MC_IOIM_READ = 13, /* read IO (Initiator mode) */
+ BFI_MC_IOIM_WRITE = 14, /* write IO (Initiator mode) */
+ BFI_MC_IOIM_IO = 15, /* IO (Initiator mode) */
+ BFI_MC_IOIM = 16, /* IO (Initiator mode) */
+ BFI_MC_IOIM_IOCOM = 17, /* good IO completion */
+ BFI_MC_TSKIM = 18, /* Initiator Task management */
+ BFI_MC_SBOOT = 19, /* SAN boot services */
+ BFI_MC_IPFC = 20, /* IP over FC Msgs */
+ BFI_MC_PORT = 21, /* Physical port */
+ BFI_MC_MAX = 32
+};
+
+#define BFI_IOC_MAX_CQS 4
+#define BFI_IOC_MAX_CQS_ASIC 8
+#define BFI_IOC_MSGLEN_MAX 32 /* 32 bytes */
+
+#pragma pack()
+
+#endif /* __BFI_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_boot.h b/drivers/scsi/bfa/include/bfi/bfi_boot.h
new file mode 100644
index 000000000000..5955afe7d108
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_boot.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * bfi_boot.h
+ */
+
+#ifndef __BFI_BOOT_H__
+#define __BFI_BOOT_H__
+
+#define BFI_BOOT_TYPE_OFF 8
+#define BFI_BOOT_PARAM_OFF 12
+
+#define BFI_BOOT_TYPE_NORMAL 0 /* param is device id */
+#define BFI_BOOT_TYPE_FLASH 1
+#define BFI_BOOT_TYPE_MEMTEST 2
+
+#define BFI_BOOT_MEMTEST_RES_ADDR 0x900
+#define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3
+
+#endif
diff --git a/drivers/scsi/bfa/include/bfi/bfi_cbreg.h b/drivers/scsi/bfa/include/bfi/bfi_cbreg.h
new file mode 100644
index 000000000000..b3bb52b565b1
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_cbreg.h
@@ -0,0 +1,305 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/*
+ * bfi_cbreg.h crossbow host block register definitions
+ *
+ * !!! Do not edit. Auto generated. !!!
+ */
+
+#ifndef __BFI_CBREG_H__
+#define __BFI_CBREG_H__
+
+
+#define HOSTFN0_INT_STATUS 0x00014000
+#define __HOSTFN0_INT_STATUS_LVL_MK 0x00f00000
+#define __HOSTFN0_INT_STATUS_LVL_SH 20
+#define __HOSTFN0_INT_STATUS_LVL(_v) ((_v) << __HOSTFN0_INT_STATUS_LVL_SH)
+#define __HOSTFN0_INT_STATUS_P 0x000fffff
+#define HOSTFN0_INT_MSK 0x00014004
+#define HOST_PAGE_NUM_FN0 0x00014008
+#define __HOST_PAGE_NUM_FN 0x000001ff
+#define HOSTFN1_INT_STATUS 0x00014100
+#define __HOSTFN1_INT_STAT_LVL_MK 0x00f00000
+#define __HOSTFN1_INT_STAT_LVL_SH 20
+#define __HOSTFN1_INT_STAT_LVL(_v) ((_v) << __HOSTFN1_INT_STAT_LVL_SH)
+#define __HOSTFN1_INT_STAT_P 0x000fffff
+#define HOSTFN1_INT_MSK 0x00014104
+#define HOST_PAGE_NUM_FN1 0x00014108
+#define APP_PLL_400_CTL_REG 0x00014204
+#define __P_400_PLL_LOCK 0x80000000
+#define __APP_PLL_400_SRAM_USE_100MHZ 0x00100000
+#define __APP_PLL_400_RESET_TIMER_MK 0x000e0000
+#define __APP_PLL_400_RESET_TIMER_SH 17
+#define __APP_PLL_400_RESET_TIMER(_v) ((_v) << __APP_PLL_400_RESET_TIMER_SH)
+#define __APP_PLL_400_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_400_CNTLMT0_1_MK 0x0000c000
+#define __APP_PLL_400_CNTLMT0_1_SH 14
+#define __APP_PLL_400_CNTLMT0_1(_v) ((_v) << __APP_PLL_400_CNTLMT0_1_SH)
+#define __APP_PLL_400_JITLMT0_1_MK 0x00003000
+#define __APP_PLL_400_JITLMT0_1_SH 12
+#define __APP_PLL_400_JITLMT0_1(_v) ((_v) << __APP_PLL_400_JITLMT0_1_SH)
+#define __APP_PLL_400_HREF 0x00000800
+#define __APP_PLL_400_HDIV 0x00000400
+#define __APP_PLL_400_P0_1_MK 0x00000300
+#define __APP_PLL_400_P0_1_SH 8
+#define __APP_PLL_400_P0_1(_v) ((_v) << __APP_PLL_400_P0_1_SH)
+#define __APP_PLL_400_Z0_2_MK 0x000000e0
+#define __APP_PLL_400_Z0_2_SH 5
+#define __APP_PLL_400_Z0_2(_v) ((_v) << __APP_PLL_400_Z0_2_SH)
+#define __APP_PLL_400_RSEL200500 0x00000010
+#define __APP_PLL_400_ENARST 0x00000008
+#define __APP_PLL_400_BYPASS 0x00000004
+#define __APP_PLL_400_LRESETN 0x00000002
+#define __APP_PLL_400_ENABLE 0x00000001
+#define APP_PLL_212_CTL_REG 0x00014208
+#define __P_212_PLL_LOCK 0x80000000
+#define __APP_PLL_212_RESET_TIMER_MK 0x000e0000
+#define __APP_PLL_212_RESET_TIMER_SH 17
+#define __APP_PLL_212_RESET_TIMER(_v) ((_v) << __APP_PLL_212_RESET_TIMER_SH)
+#define __APP_PLL_212_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_212_CNTLMT0_1_MK 0x0000c000
+#define __APP_PLL_212_CNTLMT0_1_SH 14
+#define __APP_PLL_212_CNTLMT0_1(_v) ((_v) << __APP_PLL_212_CNTLMT0_1_SH)
+#define __APP_PLL_212_JITLMT0_1_MK 0x00003000
+#define __APP_PLL_212_JITLMT0_1_SH 12
+#define __APP_PLL_212_JITLMT0_1(_v) ((_v) << __APP_PLL_212_JITLMT0_1_SH)
+#define __APP_PLL_212_HREF 0x00000800
+#define __APP_PLL_212_HDIV 0x00000400
+#define __APP_PLL_212_P0_1_MK 0x00000300
+#define __APP_PLL_212_P0_1_SH 8
+#define __APP_PLL_212_P0_1(_v) ((_v) << __APP_PLL_212_P0_1_SH)
+#define __APP_PLL_212_Z0_2_MK 0x000000e0
+#define __APP_PLL_212_Z0_2_SH 5
+#define __APP_PLL_212_Z0_2(_v) ((_v) << __APP_PLL_212_Z0_2_SH)
+#define __APP_PLL_212_RSEL200500 0x00000010
+#define __APP_PLL_212_ENARST 0x00000008
+#define __APP_PLL_212_BYPASS 0x00000004
+#define __APP_PLL_212_LRESETN 0x00000002
+#define __APP_PLL_212_ENABLE 0x00000001
+#define HOST_SEM0_REG 0x00014230
+#define __HOST_SEMAPHORE 0x00000001
+#define HOST_SEM1_REG 0x00014234
+#define HOST_SEM2_REG 0x00014238
+#define HOST_SEM3_REG 0x0001423c
+#define HOST_SEM0_INFO_REG 0x00014240
+#define HOST_SEM1_INFO_REG 0x00014244
+#define HOST_SEM2_INFO_REG 0x00014248
+#define HOST_SEM3_INFO_REG 0x0001424c
+#define HOSTFN0_LPU0_CMD_STAT 0x00019000
+#define __HOSTFN0_LPU0_MBOX_INFO_MK 0xfffffffe
+#define __HOSTFN0_LPU0_MBOX_INFO_SH 1
+#define __HOSTFN0_LPU0_MBOX_INFO(_v) ((_v) << __HOSTFN0_LPU0_MBOX_INFO_SH)
+#define __HOSTFN0_LPU0_MBOX_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN0_CMD_STAT 0x00019008
+#define __LPU0_HOSTFN0_MBOX_INFO_MK 0xfffffffe
+#define __LPU0_HOSTFN0_MBOX_INFO_SH 1
+#define __LPU0_HOSTFN0_MBOX_INFO(_v) ((_v) << __LPU0_HOSTFN0_MBOX_INFO_SH)
+#define __LPU0_HOSTFN0_MBOX_CMD_STATUS 0x00000001
+#define HOSTFN1_LPU1_CMD_STAT 0x00019014
+#define __HOSTFN1_LPU1_MBOX_INFO_MK 0xfffffffe
+#define __HOSTFN1_LPU1_MBOX_INFO_SH 1
+#define __HOSTFN1_LPU1_MBOX_INFO(_v) ((_v) << __HOSTFN1_LPU1_MBOX_INFO_SH)
+#define __HOSTFN1_LPU1_MBOX_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN1_CMD_STAT 0x0001901c
+#define __LPU1_HOSTFN1_MBOX_INFO_MK 0xfffffffe
+#define __LPU1_HOSTFN1_MBOX_INFO_SH 1
+#define __LPU1_HOSTFN1_MBOX_INFO(_v) ((_v) << __LPU1_HOSTFN1_MBOX_INFO_SH)
+#define __LPU1_HOSTFN1_MBOX_CMD_STATUS 0x00000001
+#define CPE_Q0_DEPTH 0x00010014
+#define CPE_Q0_PI 0x0001001c
+#define CPE_Q0_CI 0x00010020
+#define CPE_Q1_DEPTH 0x00010034
+#define CPE_Q1_PI 0x0001003c
+#define CPE_Q1_CI 0x00010040
+#define CPE_Q2_DEPTH 0x00010054
+#define CPE_Q2_PI 0x0001005c
+#define CPE_Q2_CI 0x00010060
+#define CPE_Q3_DEPTH 0x00010074
+#define CPE_Q3_PI 0x0001007c
+#define CPE_Q3_CI 0x00010080
+#define CPE_Q4_DEPTH 0x00010094
+#define CPE_Q4_PI 0x0001009c
+#define CPE_Q4_CI 0x000100a0
+#define CPE_Q5_DEPTH 0x000100b4
+#define CPE_Q5_PI 0x000100bc
+#define CPE_Q5_CI 0x000100c0
+#define CPE_Q6_DEPTH 0x000100d4
+#define CPE_Q6_PI 0x000100dc
+#define CPE_Q6_CI 0x000100e0
+#define CPE_Q7_DEPTH 0x000100f4
+#define CPE_Q7_PI 0x000100fc
+#define CPE_Q7_CI 0x00010100
+#define RME_Q0_DEPTH 0x00011014
+#define RME_Q0_PI 0x0001101c
+#define RME_Q0_CI 0x00011020
+#define RME_Q1_DEPTH 0x00011034
+#define RME_Q1_PI 0x0001103c
+#define RME_Q1_CI 0x00011040
+#define RME_Q2_DEPTH 0x00011054
+#define RME_Q2_PI 0x0001105c
+#define RME_Q2_CI 0x00011060
+#define RME_Q3_DEPTH 0x00011074
+#define RME_Q3_PI 0x0001107c
+#define RME_Q3_CI 0x00011080
+#define RME_Q4_DEPTH 0x00011094
+#define RME_Q4_PI 0x0001109c
+#define RME_Q4_CI 0x000110a0
+#define RME_Q5_DEPTH 0x000110b4
+#define RME_Q5_PI 0x000110bc
+#define RME_Q5_CI 0x000110c0
+#define RME_Q6_DEPTH 0x000110d4
+#define RME_Q6_PI 0x000110dc
+#define RME_Q6_CI 0x000110e0
+#define RME_Q7_DEPTH 0x000110f4
+#define RME_Q7_PI 0x000110fc
+#define RME_Q7_CI 0x00011100
+#define PSS_CTL_REG 0x00018800
+#define __PSS_I2C_CLK_DIV_MK 0x00030000
+#define __PSS_I2C_CLK_DIV_SH 16
+#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH)
+#define __PSS_LMEM_INIT_DONE 0x00001000
+#define __PSS_LMEM_RESET 0x00000200
+#define __PSS_LMEM_INIT_EN 0x00000100
+#define __PSS_LPU1_RESET 0x00000002
+#define __PSS_LPU0_RESET 0x00000001
+
+
+/*
+ * These definitions are either in error/missing in spec. Its auto-generated
+ * from hard coded values in regparse.pl.
+ */
+#define __EMPHPOST_AT_4G_MK_FIX 0x0000001c
+#define __EMPHPOST_AT_4G_SH_FIX 0x00000002
+#define __EMPHPRE_AT_4G_FIX 0x00000003
+#define __SFP_TXRATE_EN_FIX 0x00000100
+#define __SFP_RXRATE_EN_FIX 0x00000080
+
+
+/*
+ * These register definitions are auto-generated from hard coded values
+ * in regparse.pl.
+ */
+#define HOSTFN0_LPU_MBOX0_0 0x00019200
+#define HOSTFN1_LPU_MBOX0_8 0x00019260
+#define LPU_HOSTFN0_MBOX0_0 0x00019280
+#define LPU_HOSTFN1_MBOX0_8 0x000192e0
+
+
+/*
+ * These register mapping definitions are auto-generated from mapping tables
+ * in regparse.pl.
+ */
+#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG
+#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG
+#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG
+#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG
+#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG
+
+#define CPE_Q_DEPTH(__n) \
+ (CPE_Q0_DEPTH + (__n) * (CPE_Q1_DEPTH - CPE_Q0_DEPTH))
+#define CPE_Q_PI(__n) \
+ (CPE_Q0_PI + (__n) * (CPE_Q1_PI - CPE_Q0_PI))
+#define CPE_Q_CI(__n) \
+ (CPE_Q0_CI + (__n) * (CPE_Q1_CI - CPE_Q0_CI))
+#define RME_Q_DEPTH(__n) \
+ (RME_Q0_DEPTH + (__n) * (RME_Q1_DEPTH - RME_Q0_DEPTH))
+#define RME_Q_PI(__n) \
+ (RME_Q0_PI + (__n) * (RME_Q1_PI - RME_Q0_PI))
+#define RME_Q_CI(__n) \
+ (RME_Q0_CI + (__n) * (RME_Q1_CI - RME_Q0_CI))
+
+#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+#define CPE_Q_MASK(__q) ((__q) & 0x3)
+#define RME_Q_MASK(__q) ((__q) & 0x3)
+
+
+/*
+ * PCI MSI-X vector defines
+ */
+enum {
+ BFA_MSIX_CPE_Q0 = 0,
+ BFA_MSIX_CPE_Q1 = 1,
+ BFA_MSIX_CPE_Q2 = 2,
+ BFA_MSIX_CPE_Q3 = 3,
+ BFA_MSIX_CPE_Q4 = 4,
+ BFA_MSIX_CPE_Q5 = 5,
+ BFA_MSIX_CPE_Q6 = 6,
+ BFA_MSIX_CPE_Q7 = 7,
+ BFA_MSIX_RME_Q0 = 8,
+ BFA_MSIX_RME_Q1 = 9,
+ BFA_MSIX_RME_Q2 = 10,
+ BFA_MSIX_RME_Q3 = 11,
+ BFA_MSIX_RME_Q4 = 12,
+ BFA_MSIX_RME_Q5 = 13,
+ BFA_MSIX_RME_Q6 = 14,
+ BFA_MSIX_RME_Q7 = 15,
+ BFA_MSIX_ERR_EMC = 16,
+ BFA_MSIX_ERR_LPU0 = 17,
+ BFA_MSIX_ERR_LPU1 = 18,
+ BFA_MSIX_ERR_PSS = 19,
+ BFA_MSIX_MBOX_LPU0 = 20,
+ BFA_MSIX_MBOX_LPU1 = 21,
+ BFA_MSIX_CB_MAX = 22,
+};
+
+/*
+ * And corresponding host interrupt status bit field defines
+ */
+#define __HFN_INT_CPE_Q0 0x00000001U
+#define __HFN_INT_CPE_Q1 0x00000002U
+#define __HFN_INT_CPE_Q2 0x00000004U
+#define __HFN_INT_CPE_Q3 0x00000008U
+#define __HFN_INT_CPE_Q4 0x00000010U
+#define __HFN_INT_CPE_Q5 0x00000020U
+#define __HFN_INT_CPE_Q6 0x00000040U
+#define __HFN_INT_CPE_Q7 0x00000080U
+#define __HFN_INT_RME_Q0 0x00000100U
+#define __HFN_INT_RME_Q1 0x00000200U
+#define __HFN_INT_RME_Q2 0x00000400U
+#define __HFN_INT_RME_Q3 0x00000800U
+#define __HFN_INT_RME_Q4 0x00001000U
+#define __HFN_INT_RME_Q5 0x00002000U
+#define __HFN_INT_RME_Q6 0x00004000U
+#define __HFN_INT_RME_Q7 0x00008000U
+#define __HFN_INT_ERR_EMC 0x00010000U
+#define __HFN_INT_ERR_LPU0 0x00020000U
+#define __HFN_INT_ERR_LPU1 0x00040000U
+#define __HFN_INT_ERR_PSS 0x00080000U
+#define __HFN_INT_MBOX_LPU0 0x00100000U
+#define __HFN_INT_MBOX_LPU1 0x00200000U
+#define __HFN_INT_MBOX1_LPU0 0x00400000U
+#define __HFN_INT_MBOX1_LPU1 0x00800000U
+#define __HFN_INT_CPE_MASK 0x000000ffU
+#define __HFN_INT_RME_MASK 0x0000ff00U
+
+
+/*
+ * crossbow memory map.
+ */
+#define PSS_SMEM_PAGE_START 0x8000
+#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15))
+#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff)
+
+/*
+ * End of crossbow memory map
+ */
+
+
+#endif /* __BFI_CBREG_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_cee.h b/drivers/scsi/bfa/include/bfi/bfi_cee.h
new file mode 100644
index 000000000000..0970596583ea
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_cee.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/**
+ * Copyright (c) 2006-2009 Brocade Communications Systems, Inc.
+ * All rights reserved.
+ *
+ * bfi_dcbx.h BFI Interface (Mailbox commands and related structures)
+ * between host driver and DCBX/LLDP firmware module.
+ *
+**/
+
+#ifndef __BFI_CEE_H__
+#define __BFI_CEE_H__
+
+#include <bfi/bfi.h>
+
+#pragma pack(1)
+
+
+enum bfi_cee_h2i_msgs_e {
+ BFI_CEE_H2I_GET_CFG_REQ = 1,
+ BFI_CEE_H2I_RESET_STATS = 2,
+ BFI_CEE_H2I_GET_STATS_REQ = 3,
+};
+
+
+enum bfi_cee_i2h_msgs_e {
+ BFI_CEE_I2H_GET_CFG_RSP = BFA_I2HM(1),
+ BFI_CEE_I2H_RESET_STATS_RSP = BFA_I2HM(2),
+ BFI_CEE_I2H_GET_STATS_RSP = BFA_I2HM(3),
+};
+
+
+/* Data structures */
+
+/*
+ * BFI_CEE_H2I_RESET_STATS
+ */
+struct bfi_lldp_reset_stats_s {
+ struct bfi_mhdr_s mh;
+};
+
+/*
+ * BFI_CEE_H2I_RESET_STATS
+ */
+struct bfi_cee_reset_stats_s {
+ struct bfi_mhdr_s mh;
+};
+
+/*
+ * BFI_CEE_H2I_GET_CFG_REQ
+ */
+struct bfi_cee_get_req_s {
+ struct bfi_mhdr_s mh;
+ union bfi_addr_u dma_addr;
+};
+
+
+/*
+ * BFI_CEE_I2H_GET_CFG_RSP
+ */
+struct bfi_cee_get_rsp_s {
+ struct bfi_mhdr_s mh;
+ u8 cmd_status;
+ u8 rsvd[3];
+};
+
+/*
+ * BFI_CEE_H2I_GET_STATS_REQ
+ */
+struct bfi_cee_stats_req_s {
+ struct bfi_mhdr_s mh;
+ union bfi_addr_u dma_addr;
+};
+
+
+/*
+ * BFI_CEE_I2H_GET_STATS_RSP
+ */
+struct bfi_cee_stats_rsp_s {
+ struct bfi_mhdr_s mh;
+ u8 cmd_status;
+ u8 rsvd[3];
+};
+
+
+
+union bfi_cee_h2i_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_cee_get_req_s get_req;
+ struct bfi_cee_stats_req_s stats_req;
+};
+
+
+union bfi_cee_i2h_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_cee_get_rsp_s get_rsp;
+ struct bfi_cee_stats_rsp_s stats_rsp;
+};
+
+#pragma pack()
+
+
+#endif /* __BFI_CEE_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_ctreg.h b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h
new file mode 100644
index 000000000000..d3caa58c0a0a
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_ctreg.h
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/*
+ * bfi_ctreg.h catapult host block register definitions
+ *
+ * !!! Do not edit. Auto generated. !!!
+ */
+
+#ifndef __BFI_CTREG_H__
+#define __BFI_CTREG_H__
+
+
+#define HOSTFN0_LPU_MBOX0_0 0x00019200
+#define HOSTFN1_LPU_MBOX0_8 0x00019260
+#define LPU_HOSTFN0_MBOX0_0 0x00019280
+#define LPU_HOSTFN1_MBOX0_8 0x000192e0
+#define HOSTFN2_LPU_MBOX0_0 0x00019400
+#define HOSTFN3_LPU_MBOX0_8 0x00019460
+#define LPU_HOSTFN2_MBOX0_0 0x00019480
+#define LPU_HOSTFN3_MBOX0_8 0x000194e0
+#define HOSTFN0_INT_STATUS 0x00014000
+#define __HOSTFN0_HALT_OCCURRED 0x01000000
+#define __HOSTFN0_INT_STATUS_LVL_MK 0x00f00000
+#define __HOSTFN0_INT_STATUS_LVL_SH 20
+#define __HOSTFN0_INT_STATUS_LVL(_v) ((_v) << __HOSTFN0_INT_STATUS_LVL_SH)
+#define __HOSTFN0_INT_STATUS_P_MK 0x000f0000
+#define __HOSTFN0_INT_STATUS_P_SH 16
+#define __HOSTFN0_INT_STATUS_P(_v) ((_v) << __HOSTFN0_INT_STATUS_P_SH)
+#define __HOSTFN0_INT_STATUS_F 0x0000ffff
+#define HOSTFN0_INT_MSK 0x00014004
+#define HOST_PAGE_NUM_FN0 0x00014008
+#define __HOST_PAGE_NUM_FN 0x000001ff
+#define HOST_MSIX_ERR_INDEX_FN0 0x0001400c
+#define __MSIX_ERR_INDEX_FN 0x000001ff
+#define HOSTFN1_INT_STATUS 0x00014100
+#define __HOSTFN1_HALT_OCCURRED 0x01000000
+#define __HOSTFN1_INT_STATUS_LVL_MK 0x00f00000
+#define __HOSTFN1_INT_STATUS_LVL_SH 20
+#define __HOSTFN1_INT_STATUS_LVL(_v) ((_v) << __HOSTFN1_INT_STATUS_LVL_SH)
+#define __HOSTFN1_INT_STATUS_P_MK 0x000f0000
+#define __HOSTFN1_INT_STATUS_P_SH 16
+#define __HOSTFN1_INT_STATUS_P(_v) ((_v) << __HOSTFN1_INT_STATUS_P_SH)
+#define __HOSTFN1_INT_STATUS_F 0x0000ffff
+#define HOSTFN1_INT_MSK 0x00014104
+#define HOST_PAGE_NUM_FN1 0x00014108
+#define HOST_MSIX_ERR_INDEX_FN1 0x0001410c
+#define APP_PLL_425_CTL_REG 0x00014204
+#define __P_425_PLL_LOCK 0x80000000
+#define __APP_PLL_425_SRAM_USE_100MHZ 0x00100000
+#define __APP_PLL_425_RESET_TIMER_MK 0x000e0000
+#define __APP_PLL_425_RESET_TIMER_SH 17
+#define __APP_PLL_425_RESET_TIMER(_v) ((_v) << __APP_PLL_425_RESET_TIMER_SH)
+#define __APP_PLL_425_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_425_CNTLMT0_1_MK 0x0000c000
+#define __APP_PLL_425_CNTLMT0_1_SH 14
+#define __APP_PLL_425_CNTLMT0_1(_v) ((_v) << __APP_PLL_425_CNTLMT0_1_SH)
+#define __APP_PLL_425_JITLMT0_1_MK 0x00003000
+#define __APP_PLL_425_JITLMT0_1_SH 12
+#define __APP_PLL_425_JITLMT0_1(_v) ((_v) << __APP_PLL_425_JITLMT0_1_SH)
+#define __APP_PLL_425_HREF 0x00000800
+#define __APP_PLL_425_HDIV 0x00000400
+#define __APP_PLL_425_P0_1_MK 0x00000300
+#define __APP_PLL_425_P0_1_SH 8
+#define __APP_PLL_425_P0_1(_v) ((_v) << __APP_PLL_425_P0_1_SH)
+#define __APP_PLL_425_Z0_2_MK 0x000000e0
+#define __APP_PLL_425_Z0_2_SH 5
+#define __APP_PLL_425_Z0_2(_v) ((_v) << __APP_PLL_425_Z0_2_SH)
+#define __APP_PLL_425_RSEL200500 0x00000010
+#define __APP_PLL_425_ENARST 0x00000008
+#define __APP_PLL_425_BYPASS 0x00000004
+#define __APP_PLL_425_LRESETN 0x00000002
+#define __APP_PLL_425_ENABLE 0x00000001
+#define APP_PLL_312_CTL_REG 0x00014208
+#define __P_312_PLL_LOCK 0x80000000
+#define __ENABLE_MAC_AHB_1 0x00800000
+#define __ENABLE_MAC_AHB_0 0x00400000
+#define __ENABLE_MAC_1 0x00200000
+#define __ENABLE_MAC_0 0x00100000
+#define __APP_PLL_312_RESET_TIMER_MK 0x000e0000
+#define __APP_PLL_312_RESET_TIMER_SH 17
+#define __APP_PLL_312_RESET_TIMER(_v) ((_v) << __APP_PLL_312_RESET_TIMER_SH)
+#define __APP_PLL_312_LOGIC_SOFT_RESET 0x00010000
+#define __APP_PLL_312_CNTLMT0_1_MK 0x0000c000
+#define __APP_PLL_312_CNTLMT0_1_SH 14
+#define __APP_PLL_312_CNTLMT0_1(_v) ((_v) << __APP_PLL_312_CNTLMT0_1_SH)
+#define __APP_PLL_312_JITLMT0_1_MK 0x00003000
+#define __APP_PLL_312_JITLMT0_1_SH 12
+#define __APP_PLL_312_JITLMT0_1(_v) ((_v) << __APP_PLL_312_JITLMT0_1_SH)
+#define __APP_PLL_312_HREF 0x00000800
+#define __APP_PLL_312_HDIV 0x00000400
+#define __APP_PLL_312_P0_1_MK 0x00000300
+#define __APP_PLL_312_P0_1_SH 8
+#define __APP_PLL_312_P0_1(_v) ((_v) << __APP_PLL_312_P0_1_SH)
+#define __APP_PLL_312_Z0_2_MK 0x000000e0
+#define __APP_PLL_312_Z0_2_SH 5
+#define __APP_PLL_312_Z0_2(_v) ((_v) << __APP_PLL_312_Z0_2_SH)
+#define __APP_PLL_312_RSEL200500 0x00000010
+#define __APP_PLL_312_ENARST 0x00000008
+#define __APP_PLL_312_BYPASS 0x00000004
+#define __APP_PLL_312_LRESETN 0x00000002
+#define __APP_PLL_312_ENABLE 0x00000001
+#define MBIST_CTL_REG 0x00014220
+#define __EDRAM_BISTR_START 0x00000004
+#define __MBIST_RESET 0x00000002
+#define __MBIST_START 0x00000001
+#define MBIST_STAT_REG 0x00014224
+#define __EDRAM_BISTR_STATUS 0x00000008
+#define __EDRAM_BISTR_DONE 0x00000004
+#define __MEM_BIT_STATUS 0x00000002
+#define __MBIST_DONE 0x00000001
+#define HOST_SEM0_REG 0x00014230
+#define __HOST_SEMAPHORE 0x00000001
+#define HOST_SEM1_REG 0x00014234
+#define HOST_SEM2_REG 0x00014238
+#define HOST_SEM3_REG 0x0001423c
+#define HOST_SEM0_INFO_REG 0x00014240
+#define HOST_SEM1_INFO_REG 0x00014244
+#define HOST_SEM2_INFO_REG 0x00014248
+#define HOST_SEM3_INFO_REG 0x0001424c
+#define ETH_MAC_SER_REG 0x00014288
+#define __APP_EMS_CKBUFAMPIN 0x00000020
+#define __APP_EMS_REFCLKSEL 0x00000010
+#define __APP_EMS_CMLCKSEL 0x00000008
+#define __APP_EMS_REFCKBUFEN2 0x00000004
+#define __APP_EMS_REFCKBUFEN1 0x00000002
+#define __APP_EMS_CHANNEL_SEL 0x00000001
+#define HOSTFN2_INT_STATUS 0x00014300
+#define __HOSTFN2_HALT_OCCURRED 0x01000000
+#define __HOSTFN2_INT_STATUS_LVL_MK 0x00f00000
+#define __HOSTFN2_INT_STATUS_LVL_SH 20
+#define __HOSTFN2_INT_STATUS_LVL(_v) ((_v) << __HOSTFN2_INT_STATUS_LVL_SH)
+#define __HOSTFN2_INT_STATUS_P_MK 0x000f0000
+#define __HOSTFN2_INT_STATUS_P_SH 16
+#define __HOSTFN2_INT_STATUS_P(_v) ((_v) << __HOSTFN2_INT_STATUS_P_SH)
+#define __HOSTFN2_INT_STATUS_F 0x0000ffff
+#define HOSTFN2_INT_MSK 0x00014304
+#define HOST_PAGE_NUM_FN2 0x00014308
+#define HOST_MSIX_ERR_INDEX_FN2 0x0001430c
+#define HOSTFN3_INT_STATUS 0x00014400
+#define __HALT_OCCURRED 0x01000000
+#define __HOSTFN3_INT_STATUS_LVL_MK 0x00f00000
+#define __HOSTFN3_INT_STATUS_LVL_SH 20
+#define __HOSTFN3_INT_STATUS_LVL(_v) ((_v) << __HOSTFN3_INT_STATUS_LVL_SH)
+#define __HOSTFN3_INT_STATUS_P_MK 0x000f0000
+#define __HOSTFN3_INT_STATUS_P_SH 16
+#define __HOSTFN3_INT_STATUS_P(_v) ((_v) << __HOSTFN3_INT_STATUS_P_SH)
+#define __HOSTFN3_INT_STATUS_F 0x0000ffff
+#define HOSTFN3_INT_MSK 0x00014404
+#define HOST_PAGE_NUM_FN3 0x00014408
+#define HOST_MSIX_ERR_INDEX_FN3 0x0001440c
+#define FNC_ID_REG 0x00014600
+#define __FUNCTION_NUMBER 0x00000007
+#define FNC_PERS_REG 0x00014604
+#define __F3_FUNCTION_ACTIVE 0x80000000
+#define __F3_FUNCTION_MODE 0x40000000
+#define __F3_PORT_MAP_MK 0x30000000
+#define __F3_PORT_MAP_SH 28
+#define __F3_PORT_MAP(_v) ((_v) << __F3_PORT_MAP_SH)
+#define __F3_VM_MODE 0x08000000
+#define __F3_INTX_STATUS_MK 0x07000000
+#define __F3_INTX_STATUS_SH 24
+#define __F3_INTX_STATUS(_v) ((_v) << __F3_INTX_STATUS_SH)
+#define __F2_FUNCTION_ACTIVE 0x00800000
+#define __F2_FUNCTION_MODE 0x00400000
+#define __F2_PORT_MAP_MK 0x00300000
+#define __F2_PORT_MAP_SH 20
+#define __F2_PORT_MAP(_v) ((_v) << __F2_PORT_MAP_SH)
+#define __F2_VM_MODE 0x00080000
+#define __F2_INTX_STATUS_MK 0x00070000
+#define __F2_INTX_STATUS_SH 16
+#define __F2_INTX_STATUS(_v) ((_v) << __F2_INTX_STATUS_SH)
+#define __F1_FUNCTION_ACTIVE 0x00008000
+#define __F1_FUNCTION_MODE 0x00004000
+#define __F1_PORT_MAP_MK 0x00003000
+#define __F1_PORT_MAP_SH 12
+#define __F1_PORT_MAP(_v) ((_v) << __F1_PORT_MAP_SH)
+#define __F1_VM_MODE 0x00000800
+#define __F1_INTX_STATUS_MK 0x00000700
+#define __F1_INTX_STATUS_SH 8
+#define __F1_INTX_STATUS(_v) ((_v) << __F1_INTX_STATUS_SH)
+#define __F0_FUNCTION_ACTIVE 0x00000080
+#define __F0_FUNCTION_MODE 0x00000040
+#define __F0_PORT_MAP_MK 0x00000030
+#define __F0_PORT_MAP_SH 4
+#define __F0_PORT_MAP(_v) ((_v) << __F0_PORT_MAP_SH)
+#define __F0_VM_MODE 0x00000008
+#define __F0_INTX_STATUS 0x00000007
+enum {
+ __F0_INTX_STATUS_MSIX = 0x0,
+ __F0_INTX_STATUS_INTA = 0x1,
+ __F0_INTX_STATUS_INTB = 0x2,
+ __F0_INTX_STATUS_INTC = 0x3,
+ __F0_INTX_STATUS_INTD = 0x4,
+};
+#define OP_MODE 0x0001460c
+#define __APP_ETH_CLK_LOWSPEED 0x00000004
+#define __GLOBAL_CORECLK_HALFSPEED 0x00000002
+#define __GLOBAL_FCOE_MODE 0x00000001
+#define HOST_SEM4_REG 0x00014610
+#define HOST_SEM5_REG 0x00014614
+#define HOST_SEM6_REG 0x00014618
+#define HOST_SEM7_REG 0x0001461c
+#define HOST_SEM4_INFO_REG 0x00014620
+#define HOST_SEM5_INFO_REG 0x00014624
+#define HOST_SEM6_INFO_REG 0x00014628
+#define HOST_SEM7_INFO_REG 0x0001462c
+#define HOSTFN0_LPU0_MBOX0_CMD_STAT 0x00019000
+#define __HOSTFN0_LPU0_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN0_LPU0_MBOX0_INFO_SH 1
+#define __HOSTFN0_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN0_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN0_LPU1_MBOX0_CMD_STAT 0x00019004
+#define __HOSTFN0_LPU1_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN0_LPU1_MBOX0_INFO_SH 1
+#define __HOSTFN0_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN0_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN0_LPU1_MBOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN0_MBOX0_CMD_STAT 0x00019008
+#define __LPU0_HOSTFN0_MBOX0_INFO_MK 0xfffffffe
+#define __LPU0_HOSTFN0_MBOX0_INFO_SH 1
+#define __LPU0_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN0_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN0_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN0_MBOX0_CMD_STAT 0x0001900c
+#define __LPU1_HOSTFN0_MBOX0_INFO_MK 0xfffffffe
+#define __LPU1_HOSTFN0_MBOX0_INFO_SH 1
+#define __LPU1_HOSTFN0_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN0_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN1_LPU0_MBOX0_CMD_STAT 0x00019010
+#define __HOSTFN1_LPU0_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN1_LPU0_MBOX0_INFO_SH 1
+#define __HOSTFN1_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN1_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN1_LPU1_MBOX0_CMD_STAT 0x00019014
+#define __HOSTFN1_LPU1_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN1_LPU1_MBOX0_INFO_SH 1
+#define __HOSTFN1_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN1_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN1_LPU1_MBOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN1_MBOX0_CMD_STAT 0x00019018
+#define __LPU0_HOSTFN1_MBOX0_INFO_MK 0xfffffffe
+#define __LPU0_HOSTFN1_MBOX0_INFO_SH 1
+#define __LPU0_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN1_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN1_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN1_MBOX0_CMD_STAT 0x0001901c
+#define __LPU1_HOSTFN1_MBOX0_INFO_MK 0xfffffffe
+#define __LPU1_HOSTFN1_MBOX0_INFO_SH 1
+#define __LPU1_HOSTFN1_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN1_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN1_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN2_LPU0_MBOX0_CMD_STAT 0x00019150
+#define __HOSTFN2_LPU0_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN2_LPU0_MBOX0_INFO_SH 1
+#define __HOSTFN2_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN2_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN2_LPU1_MBOX0_CMD_STAT 0x00019154
+#define __HOSTFN2_LPU1_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN2_LPU1_MBOX0_INFO_SH 1
+#define __HOSTFN2_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN2_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN2_LPU1_MBOX0BOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN2_MBOX0_CMD_STAT 0x00019158
+#define __LPU0_HOSTFN2_MBOX0_INFO_MK 0xfffffffe
+#define __LPU0_HOSTFN2_MBOX0_INFO_SH 1
+#define __LPU0_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN2_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN2_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN2_MBOX0_CMD_STAT 0x0001915c
+#define __LPU1_HOSTFN2_MBOX0_INFO_MK 0xfffffffe
+#define __LPU1_HOSTFN2_MBOX0_INFO_SH 1
+#define __LPU1_HOSTFN2_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN2_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN2_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN3_LPU0_MBOX0_CMD_STAT 0x00019160
+#define __HOSTFN3_LPU0_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN3_LPU0_MBOX0_INFO_SH 1
+#define __HOSTFN3_LPU0_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU0_MBOX0_INFO_SH)
+#define __HOSTFN3_LPU0_MBOX0_CMD_STATUS 0x00000001
+#define HOSTFN3_LPU1_MBOX0_CMD_STAT 0x00019164
+#define __HOSTFN3_LPU1_MBOX0_INFO_MK 0xfffffffe
+#define __HOSTFN3_LPU1_MBOX0_INFO_SH 1
+#define __HOSTFN3_LPU1_MBOX0_INFO(_v) ((_v) << __HOSTFN3_LPU1_MBOX0_INFO_SH)
+#define __HOSTFN3_LPU1_MBOX0_CMD_STATUS 0x00000001
+#define LPU0_HOSTFN3_MBOX0_CMD_STAT 0x00019168
+#define __LPU0_HOSTFN3_MBOX0_INFO_MK 0xfffffffe
+#define __LPU0_HOSTFN3_MBOX0_INFO_SH 1
+#define __LPU0_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU0_HOSTFN3_MBOX0_INFO_SH)
+#define __LPU0_HOSTFN3_MBOX0_CMD_STATUS 0x00000001
+#define LPU1_HOSTFN3_MBOX0_CMD_STAT 0x0001916c
+#define __LPU1_HOSTFN3_MBOX0_INFO_MK 0xfffffffe
+#define __LPU1_HOSTFN3_MBOX0_INFO_SH 1
+#define __LPU1_HOSTFN3_MBOX0_INFO(_v) ((_v) << __LPU1_HOSTFN3_MBOX0_INFO_SH)
+#define __LPU1_HOSTFN3_MBOX0_CMD_STATUS 0x00000001
+#define FW_INIT_HALT_P0 0x000191ac
+#define __FW_INIT_HALT_P 0x00000001
+#define FW_INIT_HALT_P1 0x000191bc
+#define CPE_PI_PTR_Q0 0x00038000
+#define __CPE_PI_UNUSED_MK 0xffff0000
+#define __CPE_PI_UNUSED_SH 16
+#define __CPE_PI_UNUSED(_v) ((_v) << __CPE_PI_UNUSED_SH)
+#define __CPE_PI_PTR 0x0000ffff
+#define CPE_PI_PTR_Q1 0x00038040
+#define CPE_CI_PTR_Q0 0x00038004
+#define __CPE_CI_UNUSED_MK 0xffff0000
+#define __CPE_CI_UNUSED_SH 16
+#define __CPE_CI_UNUSED(_v) ((_v) << __CPE_CI_UNUSED_SH)
+#define __CPE_CI_PTR 0x0000ffff
+#define CPE_CI_PTR_Q1 0x00038044
+#define CPE_DEPTH_Q0 0x00038008
+#define __CPE_DEPTH_UNUSED_MK 0xf8000000
+#define __CPE_DEPTH_UNUSED_SH 27
+#define __CPE_DEPTH_UNUSED(_v) ((_v) << __CPE_DEPTH_UNUSED_SH)
+#define __CPE_MSIX_VEC_INDEX_MK 0x07ff0000
+#define __CPE_MSIX_VEC_INDEX_SH 16
+#define __CPE_MSIX_VEC_INDEX(_v) ((_v) << __CPE_MSIX_VEC_INDEX_SH)
+#define __CPE_DEPTH 0x0000ffff
+#define CPE_DEPTH_Q1 0x00038048
+#define CPE_QCTRL_Q0 0x0003800c
+#define __CPE_CTRL_UNUSED30_MK 0xfc000000
+#define __CPE_CTRL_UNUSED30_SH 26
+#define __CPE_CTRL_UNUSED30(_v) ((_v) << __CPE_CTRL_UNUSED30_SH)
+#define __CPE_FUNC_INT_CTRL_MK 0x03000000
+#define __CPE_FUNC_INT_CTRL_SH 24
+#define __CPE_FUNC_INT_CTRL(_v) ((_v) << __CPE_FUNC_INT_CTRL_SH)
+enum {
+ __CPE_FUNC_INT_CTRL_DISABLE = 0x0,
+ __CPE_FUNC_INT_CTRL_F2NF = 0x1,
+ __CPE_FUNC_INT_CTRL_3QUART = 0x2,
+ __CPE_FUNC_INT_CTRL_HALF = 0x3,
+};
+#define __CPE_CTRL_UNUSED20_MK 0x00f00000
+#define __CPE_CTRL_UNUSED20_SH 20
+#define __CPE_CTRL_UNUSED20(_v) ((_v) << __CPE_CTRL_UNUSED20_SH)
+#define __CPE_SCI_TH_MK 0x000f0000
+#define __CPE_SCI_TH_SH 16
+#define __CPE_SCI_TH(_v) ((_v) << __CPE_SCI_TH_SH)
+#define __CPE_CTRL_UNUSED10_MK 0x0000c000
+#define __CPE_CTRL_UNUSED10_SH 14
+#define __CPE_CTRL_UNUSED10(_v) ((_v) << __CPE_CTRL_UNUSED10_SH)
+#define __CPE_ACK_PENDING 0x00002000
+#define __CPE_CTRL_UNUSED40_MK 0x00001c00
+#define __CPE_CTRL_UNUSED40_SH 10
+#define __CPE_CTRL_UNUSED40(_v) ((_v) << __CPE_CTRL_UNUSED40_SH)
+#define __CPE_PCIEID_MK 0x00000300
+#define __CPE_PCIEID_SH 8
+#define __CPE_PCIEID(_v) ((_v) << __CPE_PCIEID_SH)
+#define __CPE_CTRL_UNUSED00_MK 0x000000fe
+#define __CPE_CTRL_UNUSED00_SH 1
+#define __CPE_CTRL_UNUSED00(_v) ((_v) << __CPE_CTRL_UNUSED00_SH)
+#define __CPE_ESIZE 0x00000001
+#define CPE_QCTRL_Q1 0x0003804c
+#define __CPE_CTRL_UNUSED31_MK 0xfc000000
+#define __CPE_CTRL_UNUSED31_SH 26
+#define __CPE_CTRL_UNUSED31(_v) ((_v) << __CPE_CTRL_UNUSED31_SH)
+#define __CPE_CTRL_UNUSED21_MK 0x00f00000
+#define __CPE_CTRL_UNUSED21_SH 20
+#define __CPE_CTRL_UNUSED21(_v) ((_v) << __CPE_CTRL_UNUSED21_SH)
+#define __CPE_CTRL_UNUSED11_MK 0x0000c000
+#define __CPE_CTRL_UNUSED11_SH 14
+#define __CPE_CTRL_UNUSED11(_v) ((_v) << __CPE_CTRL_UNUSED11_SH)
+#define __CPE_CTRL_UNUSED41_MK 0x00001c00
+#define __CPE_CTRL_UNUSED41_SH 10
+#define __CPE_CTRL_UNUSED41(_v) ((_v) << __CPE_CTRL_UNUSED41_SH)
+#define __CPE_CTRL_UNUSED01_MK 0x000000fe
+#define __CPE_CTRL_UNUSED01_SH 1
+#define __CPE_CTRL_UNUSED01(_v) ((_v) << __CPE_CTRL_UNUSED01_SH)
+#define RME_PI_PTR_Q0 0x00038020
+#define __LATENCY_TIME_STAMP_MK 0xffff0000
+#define __LATENCY_TIME_STAMP_SH 16
+#define __LATENCY_TIME_STAMP(_v) ((_v) << __LATENCY_TIME_STAMP_SH)
+#define __RME_PI_PTR 0x0000ffff
+#define RME_PI_PTR_Q1 0x00038060
+#define RME_CI_PTR_Q0 0x00038024
+#define __DELAY_TIME_STAMP_MK 0xffff0000
+#define __DELAY_TIME_STAMP_SH 16
+#define __DELAY_TIME_STAMP(_v) ((_v) << __DELAY_TIME_STAMP_SH)
+#define __RME_CI_PTR 0x0000ffff
+#define RME_CI_PTR_Q1 0x00038064
+#define RME_DEPTH_Q0 0x00038028
+#define __RME_DEPTH_UNUSED_MK 0xf8000000
+#define __RME_DEPTH_UNUSED_SH 27
+#define __RME_DEPTH_UNUSED(_v) ((_v) << __RME_DEPTH_UNUSED_SH)
+#define __RME_MSIX_VEC_INDEX_MK 0x07ff0000
+#define __RME_MSIX_VEC_INDEX_SH 16
+#define __RME_MSIX_VEC_INDEX(_v) ((_v) << __RME_MSIX_VEC_INDEX_SH)
+#define __RME_DEPTH 0x0000ffff
+#define RME_DEPTH_Q1 0x00038068
+#define RME_QCTRL_Q0 0x0003802c
+#define __RME_INT_LATENCY_TIMER_MK 0xff000000
+#define __RME_INT_LATENCY_TIMER_SH 24
+#define __RME_INT_LATENCY_TIMER(_v) ((_v) << __RME_INT_LATENCY_TIMER_SH)
+#define __RME_INT_DELAY_TIMER_MK 0x00ff0000
+#define __RME_INT_DELAY_TIMER_SH 16
+#define __RME_INT_DELAY_TIMER(_v) ((_v) << __RME_INT_DELAY_TIMER_SH)
+#define __RME_INT_DELAY_DISABLE 0x00008000
+#define __RME_DLY_DELAY_DISABLE 0x00004000
+#define __RME_ACK_PENDING 0x00002000
+#define __RME_FULL_INTERRUPT_DISABLE 0x00001000
+#define __RME_CTRL_UNUSED10_MK 0x00000c00
+#define __RME_CTRL_UNUSED10_SH 10
+#define __RME_CTRL_UNUSED10(_v) ((_v) << __RME_CTRL_UNUSED10_SH)
+#define __RME_PCIEID_MK 0x00000300
+#define __RME_PCIEID_SH 8
+#define __RME_PCIEID(_v) ((_v) << __RME_PCIEID_SH)
+#define __RME_CTRL_UNUSED00_MK 0x000000fe
+#define __RME_CTRL_UNUSED00_SH 1
+#define __RME_CTRL_UNUSED00(_v) ((_v) << __RME_CTRL_UNUSED00_SH)
+#define __RME_ESIZE 0x00000001
+#define RME_QCTRL_Q1 0x0003806c
+#define __RME_CTRL_UNUSED11_MK 0x00000c00
+#define __RME_CTRL_UNUSED11_SH 10
+#define __RME_CTRL_UNUSED11(_v) ((_v) << __RME_CTRL_UNUSED11_SH)
+#define __RME_CTRL_UNUSED01_MK 0x000000fe
+#define __RME_CTRL_UNUSED01_SH 1
+#define __RME_CTRL_UNUSED01(_v) ((_v) << __RME_CTRL_UNUSED01_SH)
+#define PSS_CTL_REG 0x00018800
+#define __PSS_I2C_CLK_DIV_MK 0x007f0000
+#define __PSS_I2C_CLK_DIV_SH 16
+#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH)
+#define __PSS_LMEM_INIT_DONE 0x00001000
+#define __PSS_LMEM_RESET 0x00000200
+#define __PSS_LMEM_INIT_EN 0x00000100
+#define __PSS_LPU1_RESET 0x00000002
+#define __PSS_LPU0_RESET 0x00000001
+#define HQM_QSET0_RXQ_DRBL_P0 0x00038000
+#define __RXQ0_ADD_VECTORS_P 0x80000000
+#define __RXQ0_STOP_P 0x40000000
+#define __RXQ0_PRD_PTR_P 0x0000ffff
+#define HQM_QSET1_RXQ_DRBL_P0 0x00038080
+#define __RXQ1_ADD_VECTORS_P 0x80000000
+#define __RXQ1_STOP_P 0x40000000
+#define __RXQ1_PRD_PTR_P 0x0000ffff
+#define HQM_QSET0_RXQ_DRBL_P1 0x0003c000
+#define HQM_QSET1_RXQ_DRBL_P1 0x0003c080
+#define HQM_QSET0_TXQ_DRBL_P0 0x00038020
+#define __TXQ0_ADD_VECTORS_P 0x80000000
+#define __TXQ0_STOP_P 0x40000000
+#define __TXQ0_PRD_PTR_P 0x0000ffff
+#define HQM_QSET1_TXQ_DRBL_P0 0x000380a0
+#define __TXQ1_ADD_VECTORS_P 0x80000000
+#define __TXQ1_STOP_P 0x40000000
+#define __TXQ1_PRD_PTR_P 0x0000ffff
+#define HQM_QSET0_TXQ_DRBL_P1 0x0003c020
+#define HQM_QSET1_TXQ_DRBL_P1 0x0003c0a0
+#define HQM_QSET0_IB_DRBL_1_P0 0x00038040
+#define __IB1_0_ACK_P 0x80000000
+#define __IB1_0_DISABLE_P 0x40000000
+#define __IB1_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff
+#define HQM_QSET1_IB_DRBL_1_P0 0x000380c0
+#define __IB1_1_ACK_P 0x80000000
+#define __IB1_1_DISABLE_P 0x40000000
+#define __IB1_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff
+#define HQM_QSET0_IB_DRBL_1_P1 0x0003c040
+#define HQM_QSET1_IB_DRBL_1_P1 0x0003c0c0
+#define HQM_QSET0_IB_DRBL_2_P0 0x00038060
+#define __IB2_0_ACK_P 0x80000000
+#define __IB2_0_DISABLE_P 0x40000000
+#define __IB2_0_NUM_OF_ACKED_EVENTS_P 0x0000ffff
+#define HQM_QSET1_IB_DRBL_2_P0 0x000380e0
+#define __IB2_1_ACK_P 0x80000000
+#define __IB2_1_DISABLE_P 0x40000000
+#define __IB2_1_NUM_OF_ACKED_EVENTS_P 0x0000ffff
+#define HQM_QSET0_IB_DRBL_2_P1 0x0003c060
+#define HQM_QSET1_IB_DRBL_2_P1 0x0003c0e0
+
+
+/*
+ * These definitions are either in error/missing in spec. Its auto-generated
+ * from hard coded values in regparse.pl.
+ */
+#define __EMPHPOST_AT_4G_MK_FIX 0x0000001c
+#define __EMPHPOST_AT_4G_SH_FIX 0x00000002
+#define __EMPHPRE_AT_4G_FIX 0x00000003
+#define __SFP_TXRATE_EN_FIX 0x00000100
+#define __SFP_RXRATE_EN_FIX 0x00000080
+
+
+/*
+ * These register definitions are auto-generated from hard coded values
+ * in regparse.pl.
+ */
+
+
+/*
+ * These register mapping definitions are auto-generated from mapping tables
+ * in regparse.pl.
+ */
+#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG
+#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG
+#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG
+#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG
+#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG
+
+#define CPE_DEPTH_Q(__n) \
+ (CPE_DEPTH_Q0 + (__n) * (CPE_DEPTH_Q1 - CPE_DEPTH_Q0))
+#define CPE_QCTRL_Q(__n) \
+ (CPE_QCTRL_Q0 + (__n) * (CPE_QCTRL_Q1 - CPE_QCTRL_Q0))
+#define CPE_PI_PTR_Q(__n) \
+ (CPE_PI_PTR_Q0 + (__n) * (CPE_PI_PTR_Q1 - CPE_PI_PTR_Q0))
+#define CPE_CI_PTR_Q(__n) \
+ (CPE_CI_PTR_Q0 + (__n) * (CPE_CI_PTR_Q1 - CPE_CI_PTR_Q0))
+#define RME_DEPTH_Q(__n) \
+ (RME_DEPTH_Q0 + (__n) * (RME_DEPTH_Q1 - RME_DEPTH_Q0))
+#define RME_QCTRL_Q(__n) \
+ (RME_QCTRL_Q0 + (__n) * (RME_QCTRL_Q1 - RME_QCTRL_Q0))
+#define RME_PI_PTR_Q(__n) \
+ (RME_PI_PTR_Q0 + (__n) * (RME_PI_PTR_Q1 - RME_PI_PTR_Q0))
+#define RME_CI_PTR_Q(__n) \
+ (RME_CI_PTR_Q0 + (__n) * (RME_CI_PTR_Q1 - RME_CI_PTR_Q0))
+#define HQM_QSET_RXQ_DRBL_P0(__n) \
+ (HQM_QSET0_RXQ_DRBL_P0 + (__n) * (HQM_QSET1_RXQ_DRBL_P0 - \
+ HQM_QSET0_RXQ_DRBL_P0))
+#define HQM_QSET_TXQ_DRBL_P0(__n) \
+ (HQM_QSET0_TXQ_DRBL_P0 + (__n) * (HQM_QSET1_TXQ_DRBL_P0 - \
+ HQM_QSET0_TXQ_DRBL_P0))
+#define HQM_QSET_IB_DRBL_1_P0(__n) \
+ (HQM_QSET0_IB_DRBL_1_P0 + (__n) * (HQM_QSET1_IB_DRBL_1_P0 - \
+ HQM_QSET0_IB_DRBL_1_P0))
+#define HQM_QSET_IB_DRBL_2_P0(__n) \
+ (HQM_QSET0_IB_DRBL_2_P0 + (__n) * (HQM_QSET1_IB_DRBL_2_P0 - \
+ HQM_QSET0_IB_DRBL_2_P0))
+#define HQM_QSET_RXQ_DRBL_P1(__n) \
+ (HQM_QSET0_RXQ_DRBL_P1 + (__n) * (HQM_QSET1_RXQ_DRBL_P1 - \
+ HQM_QSET0_RXQ_DRBL_P1))
+#define HQM_QSET_TXQ_DRBL_P1(__n) \
+ (HQM_QSET0_TXQ_DRBL_P1 + (__n) * (HQM_QSET1_TXQ_DRBL_P1 - \
+ HQM_QSET0_TXQ_DRBL_P1))
+#define HQM_QSET_IB_DRBL_1_P1(__n) \
+ (HQM_QSET0_IB_DRBL_1_P1 + (__n) * (HQM_QSET1_IB_DRBL_1_P1 - \
+ HQM_QSET0_IB_DRBL_1_P1))
+#define HQM_QSET_IB_DRBL_2_P1(__n) \
+ (HQM_QSET0_IB_DRBL_2_P1 + (__n) * (HQM_QSET1_IB_DRBL_2_P1 - \
+ HQM_QSET0_IB_DRBL_2_P1))
+
+#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q))
+#define CPE_Q_MASK(__q) ((__q) & 0x3)
+#define RME_Q_MASK(__q) ((__q) & 0x3)
+
+
+/*
+ * PCI MSI-X vector defines
+ */
+enum {
+ BFA_MSIX_CPE_Q0 = 0,
+ BFA_MSIX_CPE_Q1 = 1,
+ BFA_MSIX_CPE_Q2 = 2,
+ BFA_MSIX_CPE_Q3 = 3,
+ BFA_MSIX_RME_Q0 = 4,
+ BFA_MSIX_RME_Q1 = 5,
+ BFA_MSIX_RME_Q2 = 6,
+ BFA_MSIX_RME_Q3 = 7,
+ BFA_MSIX_LPU_ERR = 8,
+ BFA_MSIX_CT_MAX = 9,
+};
+
+/*
+ * And corresponding host interrupt status bit field defines
+ */
+#define __HFN_INT_CPE_Q0 0x00000001U
+#define __HFN_INT_CPE_Q1 0x00000002U
+#define __HFN_INT_CPE_Q2 0x00000004U
+#define __HFN_INT_CPE_Q3 0x00000008U
+#define __HFN_INT_CPE_Q4 0x00000010U
+#define __HFN_INT_CPE_Q5 0x00000020U
+#define __HFN_INT_CPE_Q6 0x00000040U
+#define __HFN_INT_CPE_Q7 0x00000080U
+#define __HFN_INT_RME_Q0 0x00000100U
+#define __HFN_INT_RME_Q1 0x00000200U
+#define __HFN_INT_RME_Q2 0x00000400U
+#define __HFN_INT_RME_Q3 0x00000800U
+#define __HFN_INT_RME_Q4 0x00001000U
+#define __HFN_INT_RME_Q5 0x00002000U
+#define __HFN_INT_RME_Q6 0x00004000U
+#define __HFN_INT_RME_Q7 0x00008000U
+#define __HFN_INT_ERR_EMC 0x00010000U
+#define __HFN_INT_ERR_LPU0 0x00020000U
+#define __HFN_INT_ERR_LPU1 0x00040000U
+#define __HFN_INT_ERR_PSS 0x00080000U
+#define __HFN_INT_MBOX_LPU0 0x00100000U
+#define __HFN_INT_MBOX_LPU1 0x00200000U
+#define __HFN_INT_MBOX1_LPU0 0x00400000U
+#define __HFN_INT_MBOX1_LPU1 0x00800000U
+#define __HFN_INT_CPE_MASK 0x000000ffU
+#define __HFN_INT_RME_MASK 0x0000ff00U
+
+
+/*
+ * catapult memory map.
+ */
+#define LL_PGN_HQM0 0x0096
+#define LL_PGN_HQM1 0x0097
+#define PSS_SMEM_PAGE_START 0x8000
+#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15))
+#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff)
+
+/*
+ * End of catapult memory map
+ */
+
+
+#endif /* __BFI_CTREG_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_fabric.h b/drivers/scsi/bfa/include/bfi/bfi_fabric.h
new file mode 100644
index 000000000000..c0669ed41078
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_fabric.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFI_FABRIC_H__
+#define __BFI_FABRIC_H__
+
+#include <bfi/bfi.h>
+
+#pragma pack(1)
+
+enum bfi_fabric_h2i_msgs {
+ BFI_FABRIC_H2I_CREATE_REQ = 1,
+ BFI_FABRIC_H2I_DELETE_REQ = 2,
+ BFI_FABRIC_H2I_SETAUTH = 3,
+};
+
+enum bfi_fabric_i2h_msgs {
+ BFI_FABRIC_I2H_CREATE_RSP = BFA_I2HM(1),
+ BFI_FABRIC_I2H_DELETE_RSP = BFA_I2HM(2),
+ BFI_FABRIC_I2H_SETAUTH_RSP = BFA_I2HM(3),
+ BFI_FABRIC_I2H_ONLINE = BFA_I2HM(4),
+ BFI_FABRIC_I2H_OFFLINE = BFA_I2HM(5),
+};
+
+struct bfi_fabric_create_req_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u8 vf_en; /* virtual fabric enable */
+ u8 rsvd;
+ u16 vf_id; /* virtual fabric ID */
+ wwn_t pwwn; /* port name */
+ wwn_t nwwn; /* node name */
+};
+
+struct bfi_fabric_create_rsp_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 bfa_handle; /* host fabric handle */
+ u8 status; /* fabric create status */
+ u8 rsvd;
+};
+
+struct bfi_fabric_delete_req_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 fw_handle; /* firmware fabric handle */
+ u16 rsvd;
+};
+
+struct bfi_fabric_delete_rsp_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 bfa_handle; /* host fabric handle */
+ u8 status; /* fabric deletion status */
+ u8 rsvd;
+};
+
+#define BFI_FABRIC_AUTHSECRET_LEN 64
+struct bfi_fabric_setauth_req_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 fw_handle; /* f/w handle of fabric */
+ u8 algorithm;
+ u8 group;
+ u8 secret[BFI_FABRIC_AUTHSECRET_LEN];
+};
+
+union bfi_fabric_h2i_msg_u {
+ bfi_msg_t *msg;
+ struct bfi_fabric_create_req_s *create_req;
+ struct bfi_fabric_delete_req_s *delete_req;
+};
+
+union bfi_fabric_i2h_msg_u {
+ bfi_msg_t *msg;
+ struct bfi_fabric_create_rsp_s *create_rsp;
+ struct bfi_fabric_delete_rsp_s *delete_rsp;
+};
+
+#pragma pack()
+
+#endif /* __BFI_FABRIC_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_fcpim.h b/drivers/scsi/bfa/include/bfi/bfi_fcpim.h
new file mode 100644
index 000000000000..52c059fb4c3a
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_fcpim.h
@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFI_FCPIM_H__
+#define __BFI_FCPIM_H__
+
+#include "bfi.h"
+#include <protocol/fcp.h>
+
+#pragma pack(1)
+
+/*
+ * Initiator mode I-T nexus interface defines.
+ */
+
+enum bfi_itnim_h2i {
+ BFI_ITNIM_H2I_CREATE_REQ = 1, /* i-t nexus creation */
+ BFI_ITNIM_H2I_DELETE_REQ = 2, /* i-t nexus deletion */
+};
+
+enum bfi_itnim_i2h {
+ BFI_ITNIM_I2H_CREATE_RSP = BFA_I2HM(1),
+ BFI_ITNIM_I2H_DELETE_RSP = BFA_I2HM(2),
+ BFI_ITNIM_I2H_SLER_EVENT = BFA_I2HM(3),
+};
+
+struct bfi_itnim_create_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 fw_handle; /* f/w handle for itnim */
+ u8 class; /* FC class for IO */
+ u8 seq_rec; /* sequence recovery support */
+ u8 msg_no; /* seq id of the msg */
+};
+
+struct bfi_itnim_create_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 bfa_handle; /* bfa handle for itnim */
+ u8 status; /* fcp request status */
+ u8 seq_id; /* seq id of the msg */
+};
+
+struct bfi_itnim_delete_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 fw_handle; /* f/w itnim handle */
+ u8 seq_id; /* seq id of the msg */
+ u8 rsvd;
+};
+
+struct bfi_itnim_delete_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 bfa_handle; /* bfa handle for itnim */
+ u8 status; /* fcp request status */
+ u8 seq_id; /* seq id of the msg */
+};
+
+struct bfi_itnim_sler_event_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 bfa_handle; /* bfa handle for itnim */
+ u16 rsvd;
+};
+
+union bfi_itnim_h2i_msg_u {
+ struct bfi_itnim_create_req_s *create_req;
+ struct bfi_itnim_delete_req_s *delete_req;
+ struct bfi_msg_s *msg;
+};
+
+union bfi_itnim_i2h_msg_u {
+ struct bfi_itnim_create_rsp_s *create_rsp;
+ struct bfi_itnim_delete_rsp_s *delete_rsp;
+ struct bfi_itnim_sler_event_s *sler_event;
+ struct bfi_msg_s *msg;
+};
+
+/*
+ * Initiator mode IO interface defines.
+ */
+
+enum bfi_ioim_h2i {
+ BFI_IOIM_H2I_IOABORT_REQ = 1, /* IO abort request */
+ BFI_IOIM_H2I_IOCLEANUP_REQ = 2, /* IO cleanup request */
+};
+
+enum bfi_ioim_i2h {
+ BFI_IOIM_I2H_IO_RSP = BFA_I2HM(1), /* non-fp IO response */
+ BFI_IOIM_I2H_IOABORT_RSP = BFA_I2HM(2),/* ABORT rsp */
+};
+
+/**
+ * IO command DIF info
+ */
+struct bfi_ioim_dif_s {
+ u32 dif_info[4];
+};
+
+/**
+ * FCP IO messages overview
+ *
+ * @note
+ * - Max CDB length supported is 64 bytes.
+ * - SCSI Linked commands and SCSI bi-directional Commands not
+ * supported.
+ *
+ */
+struct bfi_ioim_req_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 io_tag; /* I/O tag */
+ u16 rport_hdl; /* itnim/rport firmware handle */
+ struct fcp_cmnd_s cmnd; /* IO request info */
+
+ /**
+ * SG elements array within the IO request must be double word
+ * aligned. This aligment is required to optimize SGM setup for the IO.
+ */
+ struct bfi_sge_s sges[BFI_SGE_INLINE_MAX];
+ u8 io_timeout;
+ u8 dif_en;
+ u8 rsvd_a[2];
+ struct bfi_ioim_dif_s dif;
+};
+
+/**
+ * This table shows various IO status codes from firmware and their
+ * meaning. Host driver can use these status codes to further process
+ * IO completions.
+ *
+ * BFI_IOIM_STS_OK : IO completed with error free SCSI &
+ * transport status.
+ * - io-tag can be reused.
+ *
+ * BFA_IOIM_STS_SCSI_ERR : IO completed with scsi error.
+ * - io-tag can be reused.
+ *
+ * BFI_IOIM_STS_HOST_ABORTED : IO was aborted successfully due to
+ * host request.
+ * - io-tag cannot be reused yet.
+ *
+ * BFI_IOIM_STS_ABORTED : IO was aborted successfully
+ * internally by f/w.
+ * - io-tag cannot be reused yet.
+ *
+ * BFI_IOIM_STS_TIMEDOUT : IO timedout and ABTS/RRQ is happening
+ * in the firmware and
+ * - io-tag cannot be reused yet.
+ *
+ * BFI_IOIM_STS_SQER_NEEDED : Firmware could not recover the IO
+ * with sequence level error
+ * logic and hence host needs to retry
+ * this IO with a different IO tag
+ * - io-tag cannot be used yet.
+ *
+ * BFI_IOIM_STS_NEXUS_ABORT : Second Level Error Recovery from host
+ * is required because 2 consecutive ABTS
+ * timedout and host needs logout and
+ * re-login with the target
+ * - io-tag cannot be used yet.
+ *
+ * BFI_IOIM_STS_UNDERRUN : IO completed with SCSI status good,
+ * but the data tranferred is less than
+ * the fcp data length in the command.
+ * ex. SCSI INQUIRY where transferred
+ * data length and residue count in FCP
+ * response accounts for total fcp-dl
+ * - io-tag can be reused.
+ *
+ * BFI_IOIM_STS_OVERRUN : IO completed with SCSI status good,
+ * but the data transerred is more than
+ * fcp data length in the command. ex.
+ * TAPE IOs where blocks can of unequal
+ * lengths.
+ * - io-tag can be reused.
+ *
+ * BFI_IOIM_STS_RES_FREE : Firmware has completed using io-tag
+ * during abort process
+ * - io-tag can be reused.
+ *
+ * BFI_IOIM_STS_PROTO_ERR : Firmware detected a protocol error.
+ * ex target sent more data than
+ * requested, or there was data frame
+ * loss and other reasons
+ * - io-tag cannot be used yet.
+ *
+ * BFI_IOIM_STS_DIF_ERR : Firwmare detected DIF error. ex: DIF
+ * CRC err or Ref Tag err or App tag err.
+ * - io-tag can be reused.
+ *
+ * BFA_IOIM_STS_TSK_MGT_ABORT : IO was aborted because of Task
+ * Management command from the host
+ * - io-tag can be reused.
+ *
+ * BFI_IOIM_STS_UTAG : Firmware does not know about this
+ * io_tag.
+ * - io-tag can be reused.
+ */
+enum bfi_ioim_status {
+ BFI_IOIM_STS_OK = 0,
+ BFI_IOIM_STS_HOST_ABORTED = 1,
+ BFI_IOIM_STS_ABORTED = 2,
+ BFI_IOIM_STS_TIMEDOUT = 3,
+ BFI_IOIM_STS_RES_FREE = 4,
+ BFI_IOIM_STS_SQER_NEEDED = 5,
+ BFI_IOIM_STS_PROTO_ERR = 6,
+ BFI_IOIM_STS_UTAG = 7,
+ BFI_IOIM_STS_PATHTOV = 8,
+};
+
+#define BFI_IOIM_SNSLEN (256)
+/**
+ * I/O response message
+ */
+struct bfi_ioim_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 io_tag; /* completed IO tag */
+ u16 bfa_rport_hndl; /* releated rport handle */
+ u8 io_status; /* IO completion status */
+ u8 reuse_io_tag; /* IO tag can be reused */
+ u16 abort_tag; /* host abort request tag */
+ u8 scsi_status; /* scsi status from target */
+ u8 sns_len; /* scsi sense length */
+ u8 resid_flags; /* IO residue flags */
+ u8 rsvd_a;
+ u32 residue; /* IO residual length in bytes */
+ u32 rsvd_b[3];
+};
+
+struct bfi_ioim_abort_req_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 io_tag; /* I/O tag */
+ u16 abort_tag; /* unique request tag */
+};
+
+/*
+ * Initiator mode task management command interface defines.
+ */
+
+enum bfi_tskim_h2i {
+ BFI_TSKIM_H2I_TM_REQ = 1, /* task-mgmt command */
+ BFI_TSKIM_H2I_ABORT_REQ = 2, /* task-mgmt command */
+};
+
+enum bfi_tskim_i2h {
+ BFI_TSKIM_I2H_TM_RSP = BFA_I2HM(1),
+};
+
+struct bfi_tskim_req_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 tsk_tag; /* task management tag */
+ u16 itn_fhdl; /* itn firmware handle */
+ lun_t lun; /* LU number */
+ u8 tm_flags; /* see fcp_tm_cmnd_t */
+ u8 t_secs; /* Timeout value in seconds */
+ u8 rsvd[2];
+};
+
+struct bfi_tskim_abortreq_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 tsk_tag; /* task management tag */
+ u16 rsvd;
+};
+
+enum bfi_tskim_status {
+ /*
+ * Following are FCP-4 spec defined status codes,
+ * **DO NOT CHANGE THEM **
+ */
+ BFI_TSKIM_STS_OK = 0,
+ BFI_TSKIM_STS_NOT_SUPP = 4,
+ BFI_TSKIM_STS_FAILED = 5,
+
+ /**
+ * Defined by BFA
+ */
+ BFI_TSKIM_STS_TIMEOUT = 10, /* TM request timedout */
+ BFI_TSKIM_STS_ABORTED = 11, /* Aborted on host request */
+};
+
+struct bfi_tskim_rsp_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 tsk_tag; /* task mgmt cmnd tag */
+ u8 tsk_status; /* @ref bfi_tskim_status */
+ u8 rsvd;
+};
+
+#pragma pack()
+
+#endif /* __BFI_FCPIM_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_fcxp.h b/drivers/scsi/bfa/include/bfi/bfi_fcxp.h
new file mode 100644
index 000000000000..e0e995a32828
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_fcxp.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFI_FCXP_H__
+#define __BFI_FCXP_H__
+
+#include "bfi.h"
+
+#pragma pack(1)
+
+enum bfi_fcxp_h2i {
+ BFI_FCXP_H2I_SEND_REQ = 1,
+};
+
+enum bfi_fcxp_i2h {
+ BFI_FCXP_I2H_SEND_RSP = BFA_I2HM(1),
+};
+
+#define BFA_FCXP_MAX_SGES 2
+
+/**
+ * FCXP send request structure
+ */
+struct bfi_fcxp_send_req_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 fcxp_tag; /* driver request tag */
+ u16 max_frmsz; /* max send frame size */
+ u16 vf_id; /* vsan tag if applicable */
+ u16 rport_fw_hndl; /* FW Handle for the remote port */
+ u8 class; /* FC class used for req/rsp */
+ u8 rsp_timeout; /* timeout in secs, 0-no response */
+ u8 cts; /* continue sequence */
+ u8 lp_tag; /* lport tag */
+ struct fchs_s fchs; /* request FC header structure */
+ u32 req_len; /* request payload length */
+ u32 rsp_maxlen; /* max response length expected */
+ struct bfi_sge_s req_sge[BFA_FCXP_MAX_SGES]; /* request buf */
+ struct bfi_sge_s rsp_sge[BFA_FCXP_MAX_SGES]; /* response buf */
+};
+
+/**
+ * FCXP send response structure
+ */
+struct bfi_fcxp_send_rsp_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 fcxp_tag; /* send request tag */
+ u8 req_status; /* request status */
+ u8 rsvd;
+ u32 rsp_len; /* actual response length */
+ u32 residue_len; /* residual response length */
+ struct fchs_s fchs; /* response FC header structure */
+};
+
+#pragma pack()
+
+#endif /* __BFI_FCXP_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_ioc.h b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
new file mode 100644
index 000000000000..96ef05670659
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_ioc.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFI_IOC_H__
+#define __BFI_IOC_H__
+
+#include "bfi.h"
+#include <defs/bfa_defs_ioc.h>
+
+#pragma pack(1)
+
+enum bfi_ioc_h2i_msgs {
+ BFI_IOC_H2I_ENABLE_REQ = 1,
+ BFI_IOC_H2I_DISABLE_REQ = 2,
+ BFI_IOC_H2I_GETATTR_REQ = 3,
+ BFI_IOC_H2I_DBG_SYNC = 4,
+ BFI_IOC_H2I_DBG_DUMP = 5,
+};
+
+enum bfi_ioc_i2h_msgs {
+ BFI_IOC_I2H_ENABLE_REPLY = BFA_I2HM(1),
+ BFI_IOC_I2H_DISABLE_REPLY = BFA_I2HM(2),
+ BFI_IOC_I2H_GETATTR_REPLY = BFA_I2HM(3),
+ BFI_IOC_I2H_READY_EVENT = BFA_I2HM(4),
+ BFI_IOC_I2H_HBEAT = BFA_I2HM(5),
+};
+
+/**
+ * BFI_IOC_H2I_GETATTR_REQ message
+ */
+struct bfi_ioc_getattr_req_s {
+ struct bfi_mhdr_s mh;
+ union bfi_addr_u attr_addr;
+};
+
+struct bfi_ioc_attr_s {
+ wwn_t mfg_wwn;
+ mac_t mfg_mac;
+ u16 rsvd_a;
+ char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
+ u8 pcie_gen;
+ u8 pcie_lanes_orig;
+ u8 pcie_lanes;
+ u8 rx_bbcredit; /* receive buffer credits */
+ u32 adapter_prop; /* adapter properties */
+ u16 maxfrsize; /* max receive frame size */
+ char asic_rev;
+ u8 rsvd_b;
+ char fw_version[BFA_VERSION_LEN];
+ char optrom_version[BFA_VERSION_LEN];
+ struct bfa_mfg_vpd_s vpd;
+};
+
+/**
+ * BFI_IOC_I2H_GETATTR_REPLY message
+ */
+struct bfi_ioc_getattr_reply_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u8 status; /* cfg reply status */
+ u8 rsvd[3];
+};
+
+/**
+ * Firmware memory page offsets
+ */
+#define BFI_IOC_SMEM_PG0_CB (0x40)
+#define BFI_IOC_SMEM_PG0_CT (0x180)
+
+/**
+ * Firmware trace offset
+ */
+#define BFI_IOC_TRC_OFF (0x4b00)
+#define BFI_IOC_TRC_ENTS 256
+
+#define BFI_IOC_FW_SIGNATURE (0xbfadbfad)
+#define BFI_IOC_MD5SUM_SZ 4
+struct bfi_ioc_image_hdr_s {
+ u32 signature; /* constant signature */
+ u32 rsvd_a;
+ u32 exec; /* exec vector */
+ u32 param; /* parameters */
+ u32 rsvd_b[4];
+ u32 md5sum[BFI_IOC_MD5SUM_SZ];
+};
+
+/**
+ * BFI_IOC_I2H_READY_EVENT message
+ */
+struct bfi_ioc_rdy_event_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 init_status; /* init event status */
+ u8 rsvd[3];
+};
+
+struct bfi_ioc_hbeat_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u32 hb_count; /* current heart beat count */
+};
+
+/**
+ * IOC hardware/firmware state
+ */
+enum bfi_ioc_state {
+ BFI_IOC_UNINIT = 0, /* not initialized */
+ BFI_IOC_INITING = 1, /* h/w is being initialized */
+ BFI_IOC_HWINIT = 2, /* h/w is initialized */
+ BFI_IOC_CFG = 3, /* IOC configuration in progress */
+ BFI_IOC_OP = 4, /* IOC is operational */
+ BFI_IOC_DISABLING = 5, /* IOC is being disabled */
+ BFI_IOC_DISABLED = 6, /* IOC is disabled */
+ BFI_IOC_CFG_DISABLED = 7, /* IOC is being disabled;transient */
+ BFI_IOC_HBFAIL = 8, /* IOC heart-beat failure */
+ BFI_IOC_MEMTEST = 9, /* IOC is doing memtest */
+};
+
+#define BFI_IOC_ENDIAN_SIG 0x12345678
+
+enum {
+ BFI_ADAPTER_TYPE_FC = 0x01, /* FC adapters */
+ BFI_ADAPTER_TYPE_MK = 0x0f0000, /* adapter type mask */
+ BFI_ADAPTER_TYPE_SH = 16, /* adapter type shift */
+ BFI_ADAPTER_NPORTS_MK = 0xff00, /* number of ports mask */
+ BFI_ADAPTER_NPORTS_SH = 8, /* number of ports shift */
+ BFI_ADAPTER_SPEED_MK = 0xff, /* adapter speed mask */
+ BFI_ADAPTER_SPEED_SH = 0, /* adapter speed shift */
+ BFI_ADAPTER_PROTO = 0x100000, /* prototype adapaters */
+ BFI_ADAPTER_TTV = 0x200000, /* TTV debug capable */
+ BFI_ADAPTER_UNSUPP = 0x400000, /* unknown adapter type */
+};
+
+#define BFI_ADAPTER_GETP(__prop, __adap_prop) \
+ (((__adap_prop) & BFI_ADAPTER_ ## __prop ## _MK) >> \
+ BFI_ADAPTER_ ## __prop ## _SH)
+#define BFI_ADAPTER_SETP(__prop, __val) \
+ ((__val) << BFI_ADAPTER_ ## __prop ## _SH)
+#define BFI_ADAPTER_IS_PROTO(__adap_type) \
+ ((__adap_type) & BFI_ADAPTER_PROTO)
+#define BFI_ADAPTER_IS_TTV(__adap_type) \
+ ((__adap_type) & BFI_ADAPTER_TTV)
+#define BFI_ADAPTER_IS_UNSUPP(__adap_type) \
+ ((__adap_type) & BFI_ADAPTER_UNSUPP)
+#define BFI_ADAPTER_IS_SPECIAL(__adap_type) \
+ ((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO | \
+ BFI_ADAPTER_UNSUPP))
+
+/**
+ * BFI_IOC_H2I_ENABLE_REQ & BFI_IOC_H2I_DISABLE_REQ messages
+ */
+struct bfi_ioc_ctrl_req_s {
+ struct bfi_mhdr_s mh;
+ u8 ioc_class;
+ u8 rsvd[3];
+};
+
+/**
+ * BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages
+ */
+struct bfi_ioc_ctrl_reply_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u8 status; /* enable/disable status */
+ u8 rsvd[3];
+};
+
+#define BFI_IOC_MSGSZ 8
+/**
+ * H2I Messages
+ */
+union bfi_ioc_h2i_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_ioc_ctrl_req_s enable_req;
+ struct bfi_ioc_ctrl_req_s disable_req;
+ struct bfi_ioc_getattr_req_s getattr_req;
+ u32 mboxmsg[BFI_IOC_MSGSZ];
+};
+
+/**
+ * I2H Messages
+ */
+union bfi_ioc_i2h_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_ioc_rdy_event_s rdy_event;
+ u32 mboxmsg[BFI_IOC_MSGSZ];
+};
+
+#pragma pack()
+
+#endif /* __BFI_IOC_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_iocfc.h b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h
new file mode 100644
index 000000000000..c3760df72575
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_iocfc.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFI_IOCFC_H__
+#define __BFI_IOCFC_H__
+
+#include "bfi.h"
+#include <defs/bfa_defs_ioc.h>
+#include <defs/bfa_defs_iocfc.h>
+#include <defs/bfa_defs_boot.h>
+
+#pragma pack(1)
+
+enum bfi_iocfc_h2i_msgs {
+ BFI_IOCFC_H2I_CFG_REQ = 1,
+ BFI_IOCFC_H2I_GET_STATS_REQ = 2,
+ BFI_IOCFC_H2I_CLEAR_STATS_REQ = 3,
+ BFI_IOCFC_H2I_SET_INTR_REQ = 4,
+ BFI_IOCFC_H2I_UPDATEQ_REQ = 5,
+};
+
+enum bfi_iocfc_i2h_msgs {
+ BFI_IOCFC_I2H_CFG_REPLY = BFA_I2HM(1),
+ BFI_IOCFC_I2H_GET_STATS_RSP = BFA_I2HM(2),
+ BFI_IOCFC_I2H_CLEAR_STATS_RSP = BFA_I2HM(3),
+ BFI_IOCFC_I2H_UPDATEQ_RSP = BFA_I2HM(5),
+};
+
+struct bfi_iocfc_cfg_s {
+ u8 num_cqs; /* Number of CQs to be used */
+ u8 sense_buf_len; /* SCSI sense length */
+ u8 trunk_enabled; /* port trunking enabled */
+ u8 trunk_ports; /* trunk ports bit map */
+ u32 endian_sig; /* endian signature of host */
+
+ /**
+ * Request and response circular queue base addresses, size and
+ * shadow index pointers.
+ */
+ union bfi_addr_u req_cq_ba[BFI_IOC_MAX_CQS];
+ union bfi_addr_u req_shadow_ci[BFI_IOC_MAX_CQS];
+ u16 req_cq_elems[BFI_IOC_MAX_CQS];
+ union bfi_addr_u rsp_cq_ba[BFI_IOC_MAX_CQS];
+ union bfi_addr_u rsp_shadow_pi[BFI_IOC_MAX_CQS];
+ u16 rsp_cq_elems[BFI_IOC_MAX_CQS];
+
+ union bfi_addr_u stats_addr; /* DMA-able address for stats */
+ union bfi_addr_u cfgrsp_addr; /* config response dma address */
+ union bfi_addr_u ioim_snsbase; /* IO sense buffer base address */
+ struct bfa_iocfc_intr_attr_s intr_attr; /* IOC interrupt attributes */
+};
+
+/**
+ * Boot target wwn information for this port. This contains either the stored
+ * or discovered boot target port wwns for the port.
+ */
+struct bfi_iocfc_bootwwns {
+ wwn_t wwn[BFA_BOOT_BOOTLUN_MAX];
+ u8 nwwns;
+ u8 rsvd[7];
+};
+
+struct bfi_iocfc_cfgrsp_s {
+ struct bfa_iocfc_fwcfg_s fwcfg;
+ struct bfa_iocfc_intr_attr_s intr_attr;
+ struct bfi_iocfc_bootwwns bootwwns;
+};
+
+/**
+ * BFI_IOCFC_H2I_CFG_REQ message
+ */
+struct bfi_iocfc_cfg_req_s {
+ struct bfi_mhdr_s mh;
+ union bfi_addr_u ioc_cfg_dma_addr;
+};
+
+/**
+ * BFI_IOCFC_I2H_CFG_REPLY message
+ */
+struct bfi_iocfc_cfg_reply_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u8 cfg_success; /* cfg reply status */
+ u8 lpu_bm; /* LPUs assigned for this IOC */
+ u8 rsvd[2];
+};
+
+/**
+ * BFI_IOCFC_H2I_GET_STATS_REQ & BFI_IOCFC_H2I_CLEAR_STATS_REQ messages
+ */
+struct bfi_iocfc_stats_req_s {
+ struct bfi_mhdr_s mh; /* msg header */
+ u32 msgtag; /* msgtag for reply */
+};
+
+/**
+ * BFI_IOCFC_I2H_GET_STATS_RSP & BFI_IOCFC_I2H_CLEAR_STATS_RSP messages
+ */
+struct bfi_iocfc_stats_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 status; /* reply status */
+ u8 rsvd[3];
+ u32 msgtag; /* msgtag for reply */
+};
+
+/**
+ * BFI_IOCFC_H2I_SET_INTR_REQ message
+ */
+struct bfi_iocfc_set_intr_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 coalesce; /* enable intr coalescing*/
+ u8 rsvd[3];
+ u16 delay; /* delay timer 0..1125us */
+ u16 latency; /* latency timer 0..225us */
+};
+
+/**
+ * BFI_IOCFC_H2I_UPDATEQ_REQ message
+ */
+struct bfi_iocfc_updateq_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u32 reqq_ba; /* reqq base addr */
+ u32 rspq_ba; /* rspq base addr */
+ u32 reqq_sci; /* reqq shadow ci */
+ u32 rspq_spi; /* rspq shadow pi */
+};
+
+/**
+ * BFI_IOCFC_I2H_UPDATEQ_RSP message
+ */
+struct bfi_iocfc_updateq_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 status; /* updateq status */
+ u8 rsvd[3];
+};
+
+/**
+ * H2I Messages
+ */
+union bfi_iocfc_h2i_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_iocfc_cfg_req_s cfg_req;
+ struct bfi_iocfc_stats_req_s stats_get;
+ struct bfi_iocfc_stats_req_s stats_clr;
+ struct bfi_iocfc_updateq_req_s updateq_req;
+ u32 mboxmsg[BFI_IOC_MSGSZ];
+};
+
+/**
+ * I2H Messages
+ */
+union bfi_iocfc_i2h_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_iocfc_cfg_reply_s cfg_reply;
+ struct bfi_iocfc_stats_rsp_s stats_get_rsp;
+ struct bfi_iocfc_stats_rsp_s stats_clr_rsp;
+ struct bfi_iocfc_updateq_rsp_s updateq_rsp;
+ u32 mboxmsg[BFI_IOC_MSGSZ];
+};
+
+#pragma pack()
+
+#endif /* __BFI_IOCFC_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_lport.h b/drivers/scsi/bfa/include/bfi/bfi_lport.h
new file mode 100644
index 000000000000..29010614bac9
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_lport.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFI_LPORT_H__
+#define __BFI_LPORT_H__
+
+#include <bfi/bfi.h>
+
+#pragma pack(1)
+
+enum bfi_lport_h2i_msgs {
+ BFI_LPORT_H2I_CREATE_REQ = 1,
+ BFI_LPORT_H2I_DELETE_REQ = 2,
+};
+
+enum bfi_lport_i2h_msgs {
+ BFI_LPORT_I2H_CREATE_RSP = BFA_I2HM(1),
+ BFI_LPORT_I2H_DELETE_RSP = BFA_I2HM(2),
+ BFI_LPORT_I2H_ONLINE = BFA_I2HM(3),
+ BFI_LPORT_I2H_OFFLINE = BFA_I2HM(4),
+};
+
+#define BFI_LPORT_MAX_SYNNAME 64
+
+enum bfi_lport_role_e {
+ BFI_LPORT_ROLE_FCPIM = 1,
+ BFI_LPORT_ROLE_FCPTM = 2,
+ BFI_LPORT_ROLE_IPFC = 4,
+};
+
+struct bfi_lport_create_req_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 fabric_fwhdl; /* parent fabric instance */
+ u8 roles; /* lport FC-4 roles */
+ u8 rsvd;
+ wwn_t pwwn; /* port name */
+ wwn_t nwwn; /* node name */
+ u8 symname[BFI_LPORT_MAX_SYNNAME];
+};
+
+struct bfi_lport_create_rsp_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u8 status; /* lport creation status */
+ u8 rsvd[3];
+};
+
+struct bfi_lport_delete_req_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 fw_handle; /* firmware lport handle */
+ u16 rsvd;
+};
+
+struct bfi_lport_delete_rsp_s {
+ bfi_mhdr_t mh; /* common msg header */
+ u16 bfa_handle; /* host lport handle */
+ u8 status; /* lport deletion status */
+ u8 rsvd;
+};
+
+union bfi_lport_h2i_msg_u {
+ bfi_msg_t *msg;
+ struct bfi_lport_create_req_s *create_req;
+ struct bfi_lport_delete_req_s *delete_req;
+};
+
+union bfi_lport_i2h_msg_u {
+ bfi_msg_t *msg;
+ struct bfi_lport_create_rsp_s *create_rsp;
+ struct bfi_lport_delete_rsp_s *delete_rsp;
+};
+
+#pragma pack()
+
+#endif /* __BFI_LPORT_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_lps.h b/drivers/scsi/bfa/include/bfi/bfi_lps.h
new file mode 100644
index 000000000000..c59d47badb4b
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_lps.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFI_LPS_H__
+#define __BFI_LPS_H__
+
+#include <bfi/bfi.h>
+
+#pragma pack(1)
+
+enum bfi_lps_h2i_msgs {
+ BFI_LPS_H2I_LOGIN_REQ = 1,
+ BFI_LPS_H2I_LOGOUT_REQ = 2,
+};
+
+enum bfi_lps_i2h_msgs {
+ BFI_LPS_H2I_LOGIN_RSP = BFA_I2HM(1),
+ BFI_LPS_H2I_LOGOUT_RSP = BFA_I2HM(2),
+};
+
+struct bfi_lps_login_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 lp_tag;
+ u8 alpa;
+ u16 pdu_size;
+ wwn_t pwwn;
+ wwn_t nwwn;
+ u8 fdisc;
+ u8 auth_en;
+ u8 rsvd[2];
+};
+
+struct bfi_lps_login_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 lp_tag;
+ u8 status;
+ u8 lsrjt_rsn;
+ u8 lsrjt_expl;
+ wwn_t port_name;
+ wwn_t node_name;
+ u16 bb_credit;
+ u8 f_port;
+ u8 npiv_en;
+ u32 lp_pid:24;
+ u32 auth_req:8;
+ mac_t lp_mac;
+ mac_t fcf_mac;
+ u8 ext_status;
+ u8 brcd_switch;/* attached peer is brcd switch */
+};
+
+struct bfi_lps_logout_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 lp_tag;
+ u8 rsvd[3];
+ wwn_t port_name;
+};
+
+struct bfi_lps_logout_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 lp_tag;
+ u8 status;
+ u8 rsvd[2];
+};
+
+union bfi_lps_h2i_msg_u {
+ struct bfi_mhdr_s *msg;
+ struct bfi_lps_login_req_s *login_req;
+ struct bfi_lps_logout_req_s *logout_req;
+};
+
+union bfi_lps_i2h_msg_u {
+ struct bfi_msg_s *msg;
+ struct bfi_lps_login_rsp_s *login_rsp;
+ struct bfi_lps_logout_rsp_s *logout_rsp;
+};
+
+#pragma pack()
+
+#endif /* __BFI_LPS_H__ */
+
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_port.h b/drivers/scsi/bfa/include/bfi/bfi_port.h
new file mode 100644
index 000000000000..3ec3bea110ba
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_port.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFI_PORT_H__
+#define __BFI_PORT_H__
+
+#include <bfi/bfi.h>
+#include <defs/bfa_defs_pport.h>
+
+#pragma pack(1)
+
+enum bfi_port_h2i {
+ BFI_PORT_H2I_ENABLE_REQ = (1),
+ BFI_PORT_H2I_DISABLE_REQ = (2),
+ BFI_PORT_H2I_GET_STATS_REQ = (3),
+ BFI_PORT_H2I_CLEAR_STATS_REQ = (4),
+};
+
+enum bfi_port_i2h {
+ BFI_PORT_I2H_ENABLE_RSP = BFA_I2HM(1),
+ BFI_PORT_I2H_DISABLE_RSP = BFA_I2HM(2),
+ BFI_PORT_I2H_GET_STATS_RSP = BFA_I2HM(3),
+ BFI_PORT_I2H_CLEAR_STATS_RSP = BFA_I2HM(4),
+};
+
+/**
+ * Generic REQ type
+ */
+struct bfi_port_generic_req_s {
+ struct bfi_mhdr_s mh; /* msg header */
+ u32 msgtag; /* msgtag for reply */
+ u32 rsvd;
+};
+
+/**
+ * Generic RSP type
+ */
+struct bfi_port_generic_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 status; /* port enable status */
+ u8 rsvd[3];
+ u32 msgtag; /* msgtag for reply */
+};
+
+/**
+ * @todo
+ * BFI_PORT_H2I_ENABLE_REQ
+ */
+
+/**
+ * @todo
+ * BFI_PORT_I2H_ENABLE_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_DISABLE_REQ
+ */
+
+/**
+ * BFI_PORT_I2H_DISABLE_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_GET_STATS_REQ
+ */
+struct bfi_port_get_stats_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ union bfi_addr_u dma_addr;
+};
+
+/**
+ * BFI_PORT_I2H_GET_STATS_RSP
+ */
+
+/**
+ * BFI_PORT_H2I_CLEAR_STATS_REQ
+ */
+
+/**
+ * BFI_PORT_I2H_CLEAR_STATS_RSP
+ */
+
+union bfi_port_h2i_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_port_generic_req_s enable_req;
+ struct bfi_port_generic_req_s disable_req;
+ struct bfi_port_get_stats_req_s getstats_req;
+ struct bfi_port_generic_req_s clearstats_req;
+};
+
+union bfi_port_i2h_msg_u {
+ struct bfi_mhdr_s mh;
+ struct bfi_port_generic_rsp_s enable_rsp;
+ struct bfi_port_generic_rsp_s disable_rsp;
+ struct bfi_port_generic_rsp_s getstats_rsp;
+ struct bfi_port_generic_rsp_s clearstats_rsp;
+};
+
+#pragma pack()
+
+#endif /* __BFI_PORT_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_pport.h b/drivers/scsi/bfa/include/bfi/bfi_pport.h
new file mode 100644
index 000000000000..c96d246851af
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_pport.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFI_PPORT_H__
+#define __BFI_PPORT_H__
+
+#include <bfi/bfi.h>
+#include <defs/bfa_defs_pport.h>
+
+#pragma pack(1)
+
+enum bfi_pport_h2i {
+ BFI_PPORT_H2I_ENABLE_REQ = (1),
+ BFI_PPORT_H2I_DISABLE_REQ = (2),
+ BFI_PPORT_H2I_GET_STATS_REQ = (3),
+ BFI_PPORT_H2I_CLEAR_STATS_REQ = (4),
+ BFI_PPORT_H2I_SET_SVC_PARAMS_REQ = (5),
+ BFI_PPORT_H2I_ENABLE_RX_VF_TAG_REQ = (6),
+ BFI_PPORT_H2I_ENABLE_TX_VF_TAG_REQ = (7),
+ BFI_PPORT_H2I_GET_QOS_STATS_REQ = (8),
+ BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ = (9),
+};
+
+enum bfi_pport_i2h {
+ BFI_PPORT_I2H_ENABLE_RSP = BFA_I2HM(1),
+ BFI_PPORT_I2H_DISABLE_RSP = BFA_I2HM(2),
+ BFI_PPORT_I2H_GET_STATS_RSP = BFA_I2HM(3),
+ BFI_PPORT_I2H_CLEAR_STATS_RSP = BFA_I2HM(4),
+ BFI_PPORT_I2H_SET_SVC_PARAMS_RSP = BFA_I2HM(5),
+ BFI_PPORT_I2H_ENABLE_RX_VF_TAG_RSP = BFA_I2HM(6),
+ BFI_PPORT_I2H_ENABLE_TX_VF_TAG_RSP = BFA_I2HM(7),
+ BFI_PPORT_I2H_EVENT = BFA_I2HM(8),
+ BFI_PPORT_I2H_GET_QOS_STATS_RSP = BFA_I2HM(9),
+ BFI_PPORT_I2H_CLEAR_QOS_STATS_RSP = BFA_I2HM(10),
+};
+
+/**
+ * Generic REQ type
+ */
+struct bfi_pport_generic_req_s {
+ struct bfi_mhdr_s mh; /* msg header */
+ u32 msgtag; /* msgtag for reply */
+};
+
+/**
+ * Generic RSP type
+ */
+struct bfi_pport_generic_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 status; /* port enable status */
+ u8 rsvd[3];
+ u32 msgtag; /* msgtag for reply */
+};
+
+/**
+ * BFI_PPORT_H2I_ENABLE_REQ
+ */
+struct bfi_pport_enable_req_s {
+ struct bfi_mhdr_s mh; /* msg header */
+ u32 rsvd1;
+ wwn_t nwwn; /* node wwn of physical port */
+ wwn_t pwwn; /* port wwn of physical port */
+ struct bfa_pport_cfg_s port_cfg; /* port configuration */
+ union bfi_addr_u stats_dma_addr; /* DMA address for stats */
+ u32 msgtag; /* msgtag for reply */
+ u32 rsvd2;
+};
+
+/**
+ * BFI_PPORT_I2H_ENABLE_RSP
+ */
+#define bfi_pport_enable_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_DISABLE_REQ
+ */
+#define bfi_pport_disable_req_t struct bfi_pport_generic_req_s
+
+/**
+ * BFI_PPORT_I2H_DISABLE_RSP
+ */
+#define bfi_pport_disable_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_GET_STATS_REQ
+ */
+#define bfi_pport_get_stats_req_t struct bfi_pport_generic_req_s
+
+/**
+ * BFI_PPORT_I2H_GET_STATS_RSP
+ */
+#define bfi_pport_get_stats_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_CLEAR_STATS_REQ
+ */
+#define bfi_pport_clear_stats_req_t struct bfi_pport_generic_req_s
+
+/**
+ * BFI_PPORT_I2H_CLEAR_STATS_RSP
+ */
+#define bfi_pport_clear_stats_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_GET_QOS_STATS_REQ
+ */
+#define bfi_pport_get_qos_stats_req_t struct bfi_pport_generic_req_s
+
+/**
+ * BFI_PPORT_H2I_GET_QOS_STATS_RSP
+ */
+#define bfi_pport_get_qos_stats_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_CLEAR_QOS_STATS_REQ
+ */
+#define bfi_pport_clear_qos_stats_req_t struct bfi_pport_generic_req_s
+
+/**
+ * BFI_PPORT_H2I_CLEAR_QOS_STATS_RSP
+ */
+#define bfi_pport_clear_qos_stats_rsp_t struct bfi_pport_generic_rsp_s
+
+/**
+ * BFI_PPORT_H2I_SET_SVC_PARAMS_REQ
+ */
+struct bfi_pport_set_svc_params_req_s {
+ struct bfi_mhdr_s mh; /* msg header */
+ u16 tx_bbcredit; /* Tx credits */
+ u16 rsvd;
+};
+
+/**
+ * BFI_PPORT_I2H_SET_SVC_PARAMS_RSP
+ */
+
+/**
+ * BFI_PPORT_I2H_EVENT
+ */
+struct bfi_pport_event_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ struct bfa_pport_link_s link_state;
+};
+
+union bfi_pport_h2i_msg_u {
+ struct bfi_mhdr_s *mhdr;
+ struct bfi_pport_enable_req_s *penable;
+ struct bfi_pport_generic_req_s *pdisable;
+ struct bfi_pport_generic_req_s *pgetstats;
+ struct bfi_pport_generic_req_s *pclearstats;
+ struct bfi_pport_set_svc_params_req_s *psetsvcparams;
+ struct bfi_pport_get_qos_stats_req_s *pgetqosstats;
+ struct bfi_pport_generic_req_s *pclearqosstats;
+};
+
+union bfi_pport_i2h_msg_u {
+ struct bfi_msg_s *msg;
+ struct bfi_pport_generic_rsp_s *enable_rsp;
+ struct bfi_pport_disable_rsp_s *disable_rsp;
+ struct bfi_pport_generic_rsp_s *getstats_rsp;
+ struct bfi_pport_clear_stats_rsp_s *clearstats_rsp;
+ struct bfi_pport_set_svc_params_rsp_s *setsvcparasm_rsp;
+ struct bfi_pport_get_qos_stats_rsp_s *getqosstats_rsp;
+ struct bfi_pport_clear_qos_stats_rsp_s *clearqosstats_rsp;
+ struct bfi_pport_event_s *event;
+};
+
+#pragma pack()
+
+#endif /* __BFI_PPORT_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_rport.h b/drivers/scsi/bfa/include/bfi/bfi_rport.h
new file mode 100644
index 000000000000..e1cd83b56ec6
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_rport.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFI_RPORT_H__
+#define __BFI_RPORT_H__
+
+#include <bfi/bfi.h>
+
+#pragma pack(1)
+
+enum bfi_rport_h2i_msgs {
+ BFI_RPORT_H2I_CREATE_REQ = 1,
+ BFI_RPORT_H2I_DELETE_REQ = 2,
+ BFI_RPORT_H2I_SET_SPEED_REQ = 3,
+};
+
+enum bfi_rport_i2h_msgs {
+ BFI_RPORT_I2H_CREATE_RSP = BFA_I2HM(1),
+ BFI_RPORT_I2H_DELETE_RSP = BFA_I2HM(2),
+ BFI_RPORT_I2H_QOS_SCN = BFA_I2HM(3),
+};
+
+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;
+ u8 fc_class; /* supported FC classes */
+ u8 vf_en; /* virtual fabric enable */
+ u16 vf_id; /* virtual fabric ID */
+};
+
+struct bfi_rport_create_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u8 status; /* rport creation status */
+ u8 rsvd[3];
+ u16 bfa_handle; /* host rport handle */
+ u16 fw_handle; /* firmware rport handle */
+ struct bfa_rport_qos_attr_s qos_attr; /* QoS Attributes */
+};
+
+struct bfa_rport_speed_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 fw_handle; /* firmware rport handle */
+ u8 speed; /*! rport's speed via RPSC */
+ u8 rsvd;
+};
+
+struct bfi_rport_delete_req_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 fw_handle; /* firmware rport handle */
+ u16 rsvd;
+};
+
+struct bfi_rport_delete_rsp_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 bfa_handle; /* host rport handle */
+ u8 status; /* rport deletion status */
+ u8 rsvd;
+};
+
+struct bfi_rport_qos_scn_s {
+ struct bfi_mhdr_s mh; /* common msg header */
+ u16 bfa_handle; /* host rport handle */
+ u16 rsvd;
+ struct bfa_rport_qos_attr_s old_qos_attr; /* Old QoS Attributes */
+ struct bfa_rport_qos_attr_s new_qos_attr; /* New QoS Attributes */
+};
+
+union bfi_rport_h2i_msg_u {
+ struct bfi_msg_s *msg;
+ struct bfi_rport_create_req_s *create_req;
+ struct bfi_rport_delete_req_s *delete_req;
+ struct bfi_rport_speed_req_s *speed_req;
+};
+
+union bfi_rport_i2h_msg_u {
+ struct bfi_msg_s *msg;
+ struct bfi_rport_create_rsp_s *create_rsp;
+ struct bfi_rport_delete_rsp_s *delete_rsp;
+ struct bfi_rport_qos_scn_s *qos_scn_evt;
+};
+
+#pragma pack()
+
+#endif /* __BFI_RPORT_H__ */
+
diff --git a/drivers/scsi/bfa/include/bfi/bfi_uf.h b/drivers/scsi/bfa/include/bfi/bfi_uf.h
new file mode 100644
index 000000000000..f328a9e7e622
--- /dev/null
+++ b/drivers/scsi/bfa/include/bfi/bfi_uf.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFI_UF_H__
+#define __BFI_UF_H__
+
+#include "bfi.h"
+
+#pragma pack(1)
+
+enum bfi_uf_h2i {
+ BFI_UF_H2I_BUF_POST = 1,
+};
+
+enum bfi_uf_i2h {
+ BFI_UF_I2H_FRM_RCVD = BFA_I2HM(1),
+};
+
+#define BFA_UF_MAX_SGES 2
+
+struct bfi_uf_buf_post_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 buf_tag; /* buffer tag */
+ u16 buf_len; /* total buffer length */
+ struct bfi_sge_s sge[BFA_UF_MAX_SGES]; /* buffer DMA SGEs */
+};
+
+struct bfi_uf_frm_rcvd_s {
+ struct bfi_mhdr_s mh; /* Common msg header */
+ u16 buf_tag; /* buffer tag */
+ u16 rsvd;
+ u16 frm_len; /* received frame length */
+ u16 xfr_len; /* tranferred length */
+};
+
+#pragma pack()
+
+#endif /* __BFI_UF_H__ */
diff --git a/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h b/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h
new file mode 100644
index 000000000000..43ba7064e81a
--- /dev/null
+++ b/drivers/scsi/bfa/include/cna/bfa_cna_trcmod.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_cna_trcmod.h CNA trace modules
+ */
+
+#ifndef __BFA_CNA_TRCMOD_H__
+#define __BFA_CNA_TRCMOD_H__
+
+#include <cs/bfa_trc.h>
+
+/*
+ * !!! Only append to the enums defined here to avoid any versioning
+ * !!! needed between trace utility and driver version
+ */
+enum {
+ BFA_TRC_CNA_CEE = 1,
+ BFA_TRC_CNA_PORT = 2,
+};
+
+#endif /* __BFA_CNA_TRCMOD_H__ */
diff --git a/drivers/scsi/bfa/include/cna/cee/bfa_cee.h b/drivers/scsi/bfa/include/cna/cee/bfa_cee.h
new file mode 100644
index 000000000000..77f297f68046
--- /dev/null
+++ b/drivers/scsi/bfa/include/cna/cee/bfa_cee.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_CEE_H__
+#define __BFA_CEE_H__
+
+#include <defs/bfa_defs_cee.h>
+#include <bfa_ioc.h>
+#include <cs/bfa_trc.h>
+#include <cs/bfa_log.h>
+
+typedef void (*bfa_cee_get_attr_cbfn_t) (void *dev, bfa_status_t status);
+typedef void (*bfa_cee_get_stats_cbfn_t) (void *dev, bfa_status_t status);
+typedef void (*bfa_cee_reset_stats_cbfn_t) (void *dev, bfa_status_t status);
+typedef void (*bfa_cee_hbfail_cbfn_t) (void *dev, bfa_status_t status);
+
+struct bfa_cee_cbfn_s {
+ bfa_cee_get_attr_cbfn_t get_attr_cbfn;
+ void *get_attr_cbarg;
+ bfa_cee_get_stats_cbfn_t get_stats_cbfn;
+ void *get_stats_cbarg;
+ bfa_cee_reset_stats_cbfn_t reset_stats_cbfn;
+ void *reset_stats_cbarg;
+};
+
+struct bfa_cee_s {
+ void *dev;
+ bfa_boolean_t get_attr_pending;
+ bfa_boolean_t get_stats_pending;
+ bfa_boolean_t reset_stats_pending;
+ bfa_status_t get_attr_status;
+ bfa_status_t get_stats_status;
+ bfa_status_t reset_stats_status;
+ struct bfa_cee_cbfn_s cbfn;
+ struct bfa_ioc_hbfail_notify_s hbfail;
+ struct bfa_trc_mod_s *trcmod;
+ struct bfa_log_mod_s *logmod;
+ struct bfa_cee_attr_s *attr;
+ struct bfa_cee_stats_s *stats;
+ struct bfa_dma_s attr_dma;
+ struct bfa_dma_s stats_dma;
+ struct bfa_ioc_s *ioc;
+ struct bfa_mbox_cmd_s get_cfg_mb;
+ struct bfa_mbox_cmd_s get_stats_mb;
+ struct bfa_mbox_cmd_s reset_stats_mb;
+};
+
+u32 bfa_cee_meminfo(void);
+void bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva,
+ u64 dma_pa);
+void bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, void *dev,
+ struct bfa_trc_mod_s *trcmod,
+ struct bfa_log_mod_s *logmod);
+void bfa_cee_detach(struct bfa_cee_s *cee);
+bfa_status_t bfa_cee_get_attr(struct bfa_cee_s *cee,
+ struct bfa_cee_attr_s *attr,
+ bfa_cee_get_attr_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_cee_get_stats(struct bfa_cee_s *cee,
+ struct bfa_cee_stats_s *stats,
+ bfa_cee_get_stats_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_cee_reset_stats(struct bfa_cee_s *cee,
+ bfa_cee_reset_stats_cbfn_t cbfn, void *cbarg);
+#endif /* __BFA_CEE_H__ */
diff --git a/drivers/scsi/bfa/include/cna/port/bfa_port.h b/drivers/scsi/bfa/include/cna/port/bfa_port.h
new file mode 100644
index 000000000000..7cbf17d3141b
--- /dev/null
+++ b/drivers/scsi/bfa/include/cna/port/bfa_port.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_PORT_H__
+#define __BFA_PORT_H__
+
+#include <defs/bfa_defs_port.h>
+#include <bfa_ioc.h>
+#include <cs/bfa_trc.h>
+#include <cs/bfa_log.h>
+
+typedef void (*bfa_port_stats_cbfn_t) (void *dev, bfa_status_t status);
+typedef void (*bfa_port_endis_cbfn_t) (void *dev, bfa_status_t status);
+
+struct bfa_port_s {
+ void *dev;
+ struct bfa_ioc_s *ioc;
+ struct bfa_trc_mod_s *trcmod;
+ struct bfa_log_mod_s *logmod;
+ u32 msgtag;
+ bfa_boolean_t stats_busy;
+ struct bfa_mbox_cmd_s stats_mb;
+ bfa_port_stats_cbfn_t stats_cbfn;
+ void *stats_cbarg;
+ bfa_status_t stats_status;
+ union bfa_pport_stats_u *stats;
+ struct bfa_dma_s stats_dma;
+ bfa_boolean_t endis_pending;
+ struct bfa_mbox_cmd_s endis_mb;
+ bfa_port_endis_cbfn_t endis_cbfn;
+ void *endis_cbarg;
+ bfa_status_t endis_status;
+ struct bfa_ioc_hbfail_notify_s hbfail;
+};
+
+void bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc,
+ void *dev, struct bfa_trc_mod_s *trcmod,
+ struct bfa_log_mod_s *logmod);
+void bfa_port_detach(struct bfa_port_s *port);
+void bfa_port_hbfail(void *arg);
+
+bfa_status_t bfa_port_get_stats(struct bfa_port_s *port,
+ union bfa_pport_stats_u *stats,
+ bfa_port_stats_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_port_clear_stats(struct bfa_port_s *port,
+ bfa_port_stats_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_port_enable(struct bfa_port_s *port,
+ bfa_port_endis_cbfn_t cbfn, void *cbarg);
+bfa_status_t bfa_port_disable(struct bfa_port_s *port,
+ bfa_port_endis_cbfn_t cbfn, void *cbarg);
+u32 bfa_port_meminfo(void);
+void bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva,
+ u64 dma_pa);
+
+#endif /* __BFA_PORT_H__ */
diff --git a/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h b/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h
new file mode 100644
index 000000000000..1563ee512218
--- /dev/null
+++ b/drivers/scsi/bfa/include/cna/pstats/ethport_defs.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved.
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __ETHPORT_DEFS_H__
+#define __ETHPORT_DEFS_H__
+
+struct bnad_drv_stats {
+ u64 netif_queue_stop;
+ u64 netif_queue_wakeup;
+ u64 tso4;
+ u64 tso6;
+ u64 tso_err;
+ u64 tcpcsum_offload;
+ u64 udpcsum_offload;
+ u64 csum_help;
+ u64 csum_help_err;
+
+ u64 hw_stats_updates;
+ u64 netif_rx_schedule;
+ u64 netif_rx_complete;
+ u64 netif_rx_dropped;
+};
+#endif
diff --git a/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h b/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h
new file mode 100644
index 000000000000..eb7548030d0f
--- /dev/null
+++ b/drivers/scsi/bfa/include/cna/pstats/phyport_defs.h
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved.
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __PHYPORT_DEFS_H__
+#define __PHYPORT_DEFS_H__
+
+#define BNA_TXF_ID_MAX 64
+#define BNA_RXF_ID_MAX 64
+
+/*
+ * Statistics
+ */
+
+/*
+ * TxF Frame Statistics
+ */
+struct bna_stats_txf {
+ u64 ucast_octets;
+ u64 ucast;
+ u64 ucast_vlan;
+
+ u64 mcast_octets;
+ u64 mcast;
+ u64 mcast_vlan;
+
+ u64 bcast_octets;
+ u64 bcast;
+ u64 bcast_vlan;
+
+ u64 errors;
+ u64 filter_vlan; /* frames filtered due to VLAN */
+ u64 filter_mac_sa; /* frames filtered due to SA check */
+};
+
+/*
+ * RxF Frame Statistics
+ */
+struct bna_stats_rxf {
+ u64 ucast_octets;
+ u64 ucast;
+ u64 ucast_vlan;
+
+ u64 mcast_octets;
+ u64 mcast;
+ u64 mcast_vlan;
+
+ u64 bcast_octets;
+ u64 bcast;
+ u64 bcast_vlan;
+ u64 frame_drops;
+};
+
+/*
+ * FC Tx Frame Statistics
+ */
+struct bna_stats_fc_tx {
+ u64 txf_ucast_octets;
+ u64 txf_ucast;
+ u64 txf_ucast_vlan;
+
+ u64 txf_mcast_octets;
+ u64 txf_mcast;
+ u64 txf_mcast_vlan;
+
+ u64 txf_bcast_octets;
+ u64 txf_bcast;
+ u64 txf_bcast_vlan;
+
+ u64 txf_parity_errors;
+ u64 txf_timeout;
+ u64 txf_fid_parity_errors;
+};
+
+/*
+ * FC Rx Frame Statistics
+ */
+struct bna_stats_fc_rx {
+ u64 rxf_ucast_octets;
+ u64 rxf_ucast;
+ u64 rxf_ucast_vlan;
+
+ u64 rxf_mcast_octets;
+ u64 rxf_mcast;
+ u64 rxf_mcast_vlan;
+
+ u64 rxf_bcast_octets;
+ u64 rxf_bcast;
+ u64 rxf_bcast_vlan;
+};
+
+/*
+ * RAD Frame Statistics
+ */
+struct cna_stats_rad {
+ u64 rx_frames;
+ u64 rx_octets;
+ u64 rx_vlan_frames;
+
+ u64 rx_ucast;
+ u64 rx_ucast_octets;
+ u64 rx_ucast_vlan;
+
+ u64 rx_mcast;
+ u64 rx_mcast_octets;
+ u64 rx_mcast_vlan;
+
+ u64 rx_bcast;
+ u64 rx_bcast_octets;
+ u64 rx_bcast_vlan;
+
+ u64 rx_drops;
+};
+
+/*
+ * BPC Tx Registers
+ */
+struct cna_stats_bpc_tx {
+ u64 tx_pause[8];
+ u64 tx_zero_pause[8]; /* Pause cancellation */
+ u64 tx_first_pause[8]; /* Pause initiation rather
+ *than retention */
+};
+
+/*
+ * BPC Rx Registers
+ */
+struct cna_stats_bpc_rx {
+ u64 rx_pause[8];
+ u64 rx_zero_pause[8]; /* Pause cancellation */
+ u64 rx_first_pause[8]; /* Pause initiation rather
+ *than retention */
+};
+
+/*
+ * MAC Rx Statistics
+ */
+struct cna_stats_mac_rx {
+ u64 frame_64; /* both rx and tx counter */
+ u64 frame_65_127; /* both rx and tx counter */
+ u64 frame_128_255; /* both rx and tx counter */
+ u64 frame_256_511; /* both rx and tx counter */
+ u64 frame_512_1023; /* both rx and tx counter */
+ u64 frame_1024_1518; /* both rx and tx counter */
+ u64 frame_1518_1522; /* both rx and tx counter */
+ u64 rx_bytes;
+ u64 rx_packets;
+ u64 rx_fcs_error;
+ u64 rx_multicast;
+ u64 rx_broadcast;
+ u64 rx_control_frames;
+ u64 rx_pause;
+ u64 rx_unknown_opcode;
+ u64 rx_alignment_error;
+ u64 rx_frame_length_error;
+ u64 rx_code_error;
+ u64 rx_carrier_sense_error;
+ u64 rx_undersize;
+ u64 rx_oversize;
+ u64 rx_fragments;
+ u64 rx_jabber;
+ u64 rx_drop;
+};
+
+/*
+ * MAC Tx Statistics
+ */
+struct cna_stats_mac_tx {
+ u64 tx_bytes;
+ u64 tx_packets;
+ u64 tx_multicast;
+ u64 tx_broadcast;
+ u64 tx_pause;
+ u64 tx_deferral;
+ u64 tx_excessive_deferral;
+ u64 tx_single_collision;
+ u64 tx_muliple_collision;
+ u64 tx_late_collision;
+ u64 tx_excessive_collision;
+ u64 tx_total_collision;
+ u64 tx_pause_honored;
+ u64 tx_drop;
+ u64 tx_jabber;
+ u64 tx_fcs_error;
+ u64 tx_control_frame;
+ u64 tx_oversize;
+ u64 tx_undersize;
+ u64 tx_fragments;
+};
+
+/*
+ * Complete statistics
+ */
+struct bna_stats {
+ struct cna_stats_mac_rx mac_rx_stats;
+ struct cna_stats_bpc_rx bpc_rx_stats;
+ struct cna_stats_rad rad_stats;
+ struct bna_stats_fc_rx fc_rx_stats;
+ struct cna_stats_mac_tx mac_tx_stats;
+ struct cna_stats_bpc_tx bpc_tx_stats;
+ struct bna_stats_fc_tx fc_tx_stats;
+ struct bna_stats_rxf rxf_stats[BNA_TXF_ID_MAX];
+ struct bna_stats_txf txf_stats[BNA_RXF_ID_MAX];
+};
+
+#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_checksum.h b/drivers/scsi/bfa/include/cs/bfa_checksum.h
new file mode 100644
index 000000000000..650f8d0aaff9
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_checksum.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_checksum.h BFA checksum utilities
+ */
+
+#ifndef __BFA_CHECKSUM_H__
+#define __BFA_CHECKSUM_H__
+
+static inline u32
+bfa_checksum_u32(u32 *buf, int sz)
+{
+ int i, m = sz >> 2;
+ u32 sum = 0;
+
+ for (i = 0; i < m; i++)
+ sum ^= buf[i];
+
+ return sum;
+}
+
+static inline u16
+bfa_checksum_u16(u16 *buf, int sz)
+{
+ int i, m = sz >> 1;
+ u16 sum = 0;
+
+ for (i = 0; i < m; i++)
+ sum ^= buf[i];
+
+ return sum;
+}
+
+static inline u8
+bfa_checksum_u8(u8 *buf, int sz)
+{
+ int i;
+ u8 sum = 0;
+
+ for (i = 0; i < sz; i++)
+ sum ^= buf[i];
+
+ return sum;
+}
+#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_debug.h b/drivers/scsi/bfa/include/cs/bfa_debug.h
new file mode 100644
index 000000000000..441be86b1b0f
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_debug.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_debug.h BFA debug interfaces
+ */
+
+#ifndef __BFA_DEBUG_H__
+#define __BFA_DEBUG_H__
+
+#define bfa_assert(__cond) do { \
+ if (!(__cond)) \
+ bfa_panic(__LINE__, __FILE__, #__cond); \
+} while (0)
+
+#define bfa_sm_fault(__mod, __event) do { \
+ bfa_sm_panic((__mod)->logm, __LINE__, __FILE__, __event); \
+} while (0)
+
+#ifndef BFA_PERF_BUILD
+#define bfa_assert_fp(__cond) bfa_assert(__cond)
+#else
+#define bfa_assert_fp(__cond)
+#endif
+
+struct bfa_log_mod_s;
+void bfa_panic(int line, char *file, char *panicstr);
+void bfa_sm_panic(struct bfa_log_mod_s *logm, int line, char *file, int event);
+
+#endif /* __BFA_DEBUG_H__ */
diff --git a/drivers/scsi/bfa/include/cs/bfa_log.h b/drivers/scsi/bfa/include/cs/bfa_log.h
new file mode 100644
index 000000000000..761cbe22130a
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_log.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_log.h BFA log library data structure and function definition
+ */
+
+#ifndef __BFA_LOG_H__
+#define __BFA_LOG_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_aen.h>
+
+/*
+ * BFA log module definition
+ *
+ * To create a new module id:
+ * Add a #define at the end of the list below. Select a value for your
+ * definition so that it is one (1) greater than the previous
+ * definition. Modify the definition of BFA_LOG_MODULE_ID_MAX to become
+ * your new definition.
+ * Should have no gaps in between the values because this is used in arrays.
+ * IMPORTANT: AEN_IDs must be at the begining, otherwise update bfa_defs_aen.h
+ */
+
+enum bfa_log_module_id {
+ BFA_LOG_UNUSED_ID = 0,
+
+ /* AEN defs begin */
+ BFA_LOG_AEN_MIN = BFA_LOG_UNUSED_ID,
+
+ BFA_LOG_AEN_ID_ADAPTER = BFA_LOG_AEN_MIN + BFA_AEN_CAT_ADAPTER,/* 1 */
+ BFA_LOG_AEN_ID_PORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_PORT, /* 2 */
+ BFA_LOG_AEN_ID_LPORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_LPORT, /* 3 */
+ BFA_LOG_AEN_ID_RPORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_RPORT, /* 4 */
+ BFA_LOG_AEN_ID_ITNIM = BFA_LOG_AEN_MIN + BFA_AEN_CAT_ITNIM, /* 5 */
+ BFA_LOG_AEN_ID_TIN = BFA_LOG_AEN_MIN + BFA_AEN_CAT_TIN, /* 6 */
+ BFA_LOG_AEN_ID_IPFC = BFA_LOG_AEN_MIN + BFA_AEN_CAT_IPFC, /* 7 */
+ BFA_LOG_AEN_ID_AUDIT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_AUDIT, /* 8 */
+ BFA_LOG_AEN_ID_IOC = BFA_LOG_AEN_MIN + BFA_AEN_CAT_IOC, /* 9 */
+ BFA_LOG_AEN_ID_ETHPORT = BFA_LOG_AEN_MIN + BFA_AEN_CAT_ETHPORT,/* 10 */
+
+ BFA_LOG_AEN_MAX = BFA_LOG_AEN_ID_ETHPORT,
+ /* AEN defs end */
+
+ BFA_LOG_MODULE_ID_MIN = BFA_LOG_AEN_MAX,
+
+ BFA_LOG_FW_ID = BFA_LOG_MODULE_ID_MIN + 1,
+ BFA_LOG_HAL_ID = BFA_LOG_MODULE_ID_MIN + 2,
+ BFA_LOG_FCS_ID = BFA_LOG_MODULE_ID_MIN + 3,
+ BFA_LOG_WDRV_ID = BFA_LOG_MODULE_ID_MIN + 4,
+ BFA_LOG_LINUX_ID = BFA_LOG_MODULE_ID_MIN + 5,
+ BFA_LOG_SOLARIS_ID = BFA_LOG_MODULE_ID_MIN + 6,
+
+ BFA_LOG_MODULE_ID_MAX = BFA_LOG_SOLARIS_ID,
+
+ /* Not part of any arrays */
+ BFA_LOG_MODULE_ID_ALL = BFA_LOG_MODULE_ID_MAX + 1,
+ BFA_LOG_AEN_ALL = BFA_LOG_MODULE_ID_MAX + 2,
+ BFA_LOG_DRV_ALL = BFA_LOG_MODULE_ID_MAX + 3,
+};
+
+/*
+ * BFA log catalog name
+ */
+#define BFA_LOG_CAT_NAME "BFA"
+
+/*
+ * bfa log severity values
+ */
+enum bfa_log_severity {
+ BFA_LOG_INVALID = 0,
+ BFA_LOG_CRITICAL = 1,
+ BFA_LOG_ERROR = 2,
+ BFA_LOG_WARNING = 3,
+ BFA_LOG_INFO = 4,
+ BFA_LOG_NONE = 5,
+ BFA_LOG_LEVEL_MAX = BFA_LOG_NONE
+};
+
+#define BFA_LOG_MODID_OFFSET 16
+
+
+struct bfa_log_msgdef_s {
+ u32 msg_id; /* message id */
+ int attributes; /* attributes */
+ int severity; /* severity level */
+ char *msg_value;
+ /* msg string */
+ char *message;
+ /* msg format string */
+ int arg_type; /* argument type */
+ int arg_num; /* number of argument */
+};
+
+/*
+ * supported argument type
+ */
+enum bfa_log_arg_type {
+ BFA_LOG_S = 0, /* string */
+ BFA_LOG_D, /* decimal */
+ BFA_LOG_I, /* integer */
+ BFA_LOG_O, /* oct number */
+ BFA_LOG_U, /* unsigned integer */
+ BFA_LOG_X, /* hex number */
+ BFA_LOG_F, /* floating */
+ BFA_LOG_C, /* character */
+ BFA_LOG_L, /* double */
+ BFA_LOG_P /* pointer */
+};
+
+#define BFA_LOG_ARG_TYPE 2
+#define BFA_LOG_ARG0 (0 * BFA_LOG_ARG_TYPE)
+#define BFA_LOG_ARG1 (1 * BFA_LOG_ARG_TYPE)
+#define BFA_LOG_ARG2 (2 * BFA_LOG_ARG_TYPE)
+#define BFA_LOG_ARG3 (3 * BFA_LOG_ARG_TYPE)
+
+#define BFA_LOG_GET_MOD_ID(msgid) ((msgid >> BFA_LOG_MODID_OFFSET) & 0xff)
+#define BFA_LOG_GET_MSG_IDX(msgid) (msgid & 0xffff)
+#define BFA_LOG_GET_MSG_ID(msgdef) ((msgdef)->msg_id)
+#define BFA_LOG_GET_MSG_FMT_STRING(msgdef) ((msgdef)->message)
+#define BFA_LOG_GET_SEVERITY(msgdef) ((msgdef)->severity)
+
+/*
+ * Event attributes
+ */
+#define BFA_LOG_ATTR_NONE 0
+#define BFA_LOG_ATTR_AUDIT 1
+#define BFA_LOG_ATTR_LOG 2
+#define BFA_LOG_ATTR_FFDC 4
+
+#define BFA_LOG_CREATE_ID(msw, lsw) \
+ (((u32)msw << BFA_LOG_MODID_OFFSET) | lsw)
+
+struct bfa_log_mod_s;
+
+/**
+ * callback function
+ */
+typedef void (*bfa_log_cb_t)(struct bfa_log_mod_s *log_mod, u32 msg_id,
+ const char *format, ...);
+
+
+struct bfa_log_mod_s {
+ char instance_info[16]; /* instance info */
+ int log_level[BFA_LOG_MODULE_ID_MAX + 1];
+ /* log level for modules */
+ bfa_log_cb_t cbfn; /* callback function */
+};
+
+extern int bfa_log_init(struct bfa_log_mod_s *log_mod,
+ char *instance_name, bfa_log_cb_t cbfn);
+extern int bfa_log(struct bfa_log_mod_s *log_mod, u32 msg_id, ...);
+extern bfa_status_t bfa_log_set_level(struct bfa_log_mod_s *log_mod,
+ int mod_id, enum bfa_log_severity log_level);
+extern bfa_status_t bfa_log_set_level_all(struct bfa_log_mod_s *log_mod,
+ enum bfa_log_severity log_level);
+extern bfa_status_t bfa_log_set_level_aen(struct bfa_log_mod_s *log_mod,
+ enum bfa_log_severity log_level);
+extern enum bfa_log_severity bfa_log_get_level(struct bfa_log_mod_s *log_mod,
+ int mod_id);
+extern enum bfa_log_severity bfa_log_get_msg_level(
+ struct bfa_log_mod_s *log_mod, u32 msg_id);
+/*
+ * array of messages generated from xml files
+ */
+extern struct bfa_log_msgdef_s bfa_log_msg_array[];
+
+#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_perf.h b/drivers/scsi/bfa/include/cs/bfa_perf.h
new file mode 100644
index 000000000000..45aa5f978ff5
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_perf.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFAD_PERF_H__
+#define __BFAD_PERF_H__
+
+#ifdef BFAD_PERF_BUILD
+
+#undef bfa_trc
+#undef bfa_trc32
+#undef bfa_assert
+#undef BFA_TRC_FILE
+
+#define bfa_trc(_trcp, _data)
+#define bfa_trc32(_trcp, _data)
+#define bfa_assert(__cond)
+#define BFA_TRC_FILE(__mod, __submod)
+
+#endif
+
+#endif /* __BFAD_PERF_H__ */
diff --git a/drivers/scsi/bfa/include/cs/bfa_plog.h b/drivers/scsi/bfa/include/cs/bfa_plog.h
new file mode 100644
index 000000000000..670f86e5fc6e
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_plog.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_PORTLOG_H__
+#define __BFA_PORTLOG_H__
+
+#include "protocol/fc.h"
+#include <defs/bfa_defs_types.h>
+
+#define BFA_PL_NLOG_ENTS 256
+#define BFA_PL_LOG_REC_INCR(_x) ((_x)++, (_x) %= BFA_PL_NLOG_ENTS)
+
+#define BFA_PL_STRING_LOG_SZ 32 /* number of chars in string log */
+#define BFA_PL_INT_LOG_SZ 8 /* number of integers in the integer log */
+
+enum bfa_plog_log_type {
+ BFA_PL_LOG_TYPE_INVALID = 0,
+ BFA_PL_LOG_TYPE_INT = 1,
+ BFA_PL_LOG_TYPE_STRING = 2,
+};
+
+/*
+ * the (fixed size) record format for each entry in the portlog
+ */
+struct bfa_plog_rec_s {
+ u32 tv; /* Filled by the portlog driver when the *
+ * entry is added to the circular log. */
+ u8 port; /* Source port that logged this entry. CM
+ * entities will use 0xFF */
+ u8 mid; /* Integer value to be used by all entities *
+ * while logging. The module id to string *
+ * conversion will be done by BFAL. See
+ * enum bfa_plog_mid */
+ u8 eid; /* indicates Rx, Tx, IOCTL, etc. See
+ * enum bfa_plog_eid */
+ u8 log_type; /* indicates string log or integer log.
+ * see bfa_plog_log_type_t */
+ u8 log_num_ints;
+ /*
+ * interpreted only if log_type is INT_LOG. indicates number of
+ * integers in the int_log[] (0-PL_INT_LOG_SZ).
+ */
+ u8 rsvd;
+ u16 misc; /* can be used to indicate fc frame length,
+ *etc.. */
+ union {
+ char string_log[BFA_PL_STRING_LOG_SZ];
+ u32 int_log[BFA_PL_INT_LOG_SZ];
+ } log_entry;
+
+};
+
+/*
+ * the following #defines will be used by the logging entities to indicate
+ * their module id. BFAL will convert the integer value to string format
+ *
+* process to be used while changing the following #defines:
+ * - Always add new entries at the end
+ * - define corresponding string in BFAL
+ * - Do not remove any entry or rearrange the order.
+ */
+enum bfa_plog_mid {
+ BFA_PL_MID_INVALID = 0,
+ BFA_PL_MID_DEBUG = 1,
+ BFA_PL_MID_DRVR = 2,
+ BFA_PL_MID_HAL = 3,
+ BFA_PL_MID_HAL_FCXP = 4,
+ BFA_PL_MID_HAL_UF = 5,
+ BFA_PL_MID_FCS = 6,
+ BFA_PL_MID_MAX = 7
+};
+
+#define BFA_PL_MID_STRLEN 8
+struct bfa_plog_mid_strings_s {
+ char m_str[BFA_PL_MID_STRLEN];
+};
+
+/*
+ * the following #defines will be used by the logging entities to indicate
+ * their event type. BFAL will convert the integer value to string format
+ *
+* process to be used while changing the following #defines:
+ * - Always add new entries at the end
+ * - define corresponding string in BFAL
+ * - Do not remove any entry or rearrange the order.
+ */
+enum bfa_plog_eid {
+ BFA_PL_EID_INVALID = 0,
+ BFA_PL_EID_IOC_DISABLE = 1,
+ BFA_PL_EID_IOC_ENABLE = 2,
+ BFA_PL_EID_PORT_DISABLE = 3,
+ BFA_PL_EID_PORT_ENABLE = 4,
+ BFA_PL_EID_PORT_ST_CHANGE = 5,
+ BFA_PL_EID_TX = 6,
+ BFA_PL_EID_TX_ACK1 = 7,
+ BFA_PL_EID_TX_RJT = 8,
+ BFA_PL_EID_TX_BSY = 9,
+ BFA_PL_EID_RX = 10,
+ BFA_PL_EID_RX_ACK1 = 11,
+ BFA_PL_EID_RX_RJT = 12,
+ BFA_PL_EID_RX_BSY = 13,
+ BFA_PL_EID_CT_IN = 14,
+ BFA_PL_EID_CT_OUT = 15,
+ BFA_PL_EID_DRIVER_START = 16,
+ BFA_PL_EID_RSCN = 17,
+ BFA_PL_EID_DEBUG = 18,
+ BFA_PL_EID_MISC = 19,
+ BFA_PL_EID_MAX = 20
+};
+
+#define BFA_PL_ENAME_STRLEN 8
+struct bfa_plog_eid_strings_s {
+ char e_str[BFA_PL_ENAME_STRLEN];
+};
+
+#define BFA_PL_SIG_LEN 8
+#define BFA_PL_SIG_STR "12pl123"
+
+/*
+ * per port circular log buffer
+ */
+struct bfa_plog_s {
+ char plog_sig[BFA_PL_SIG_LEN]; /* Start signature */
+ u8 plog_enabled;
+ u8 rsvd[7];
+ u32 ticks;
+ u16 head;
+ u16 tail;
+ struct bfa_plog_rec_s plog_recs[BFA_PL_NLOG_ENTS];
+};
+
+void bfa_plog_init(struct bfa_plog_s *plog);
+void bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event, u16 misc, char *log_str);
+void bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event, u16 misc,
+ u32 *intarr, u32 num_ints);
+void bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event, u16 misc,
+ struct fchs_s *fchdr);
+void bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event, u16 misc,
+ struct fchs_s *fchdr, u32 pld_w0);
+void bfa_plog_clear(struct bfa_plog_s *plog);
+void bfa_plog_enable(struct bfa_plog_s *plog);
+void bfa_plog_disable(struct bfa_plog_s *plog);
+bfa_boolean_t bfa_plog_get_setting(struct bfa_plog_s *plog);
+
+#endif /* __BFA_PORTLOG_H__ */
diff --git a/drivers/scsi/bfa/include/cs/bfa_q.h b/drivers/scsi/bfa/include/cs/bfa_q.h
new file mode 100644
index 000000000000..ea895facedbc
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_q.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_q.h Circular queue definitions.
+ */
+
+#ifndef __BFA_Q_H__
+#define __BFA_Q_H__
+
+#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next))
+#define bfa_q_next(_qe) (((struct list_head *) (_qe))->next)
+#define bfa_q_prev(_qe) (((struct list_head *) (_qe))->prev)
+
+/*
+ * bfa_q_qe_init - to initialize a queue element
+ */
+#define bfa_q_qe_init(_qe) { \
+ bfa_q_next(_qe) = (struct list_head *) NULL; \
+ bfa_q_prev(_qe) = (struct list_head *) NULL; \
+}
+
+/*
+ * bfa_q_deq - dequeue an element from head of the queue
+ */
+#define bfa_q_deq(_q, _qe) { \
+ if (!list_empty(_q)) { \
+ (*((struct list_head **) (_qe))) = bfa_q_next(_q); \
+ bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) = \
+ (struct list_head *) (_q); \
+ bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe)); \
+ BFA_Q_DBG_INIT(*((struct list_head **) _qe)); \
+ } else { \
+ *((struct list_head **) (_qe)) = (struct list_head *) NULL; \
+ } \
+}
+
+/*
+ * bfa_q_deq_tail - dequeue an element from tail of the queue
+ */
+#define bfa_q_deq_tail(_q, _qe) { \
+ if (!list_empty(_q)) { \
+ *((struct list_head **) (_qe)) = bfa_q_prev(_q); \
+ bfa_q_next(bfa_q_prev(*((struct list_head **) _qe))) = \
+ (struct list_head *) (_q); \
+ bfa_q_prev(_q) = bfa_q_prev(*(struct list_head **) _qe); \
+ BFA_Q_DBG_INIT(*((struct list_head **) _qe)); \
+ } else { \
+ *((struct list_head **) (_qe)) = (struct list_head *) NULL; \
+ } \
+}
+
+/*
+ * #ifdef BFA_DEBUG (Using bfa_assert to check for debug_build is not
+ * consistent across modules)
+ */
+#ifndef BFA_PERF_BUILD
+#define BFA_Q_DBG_INIT(_qe) bfa_q_qe_init(_qe)
+#else
+#define BFA_Q_DBG_INIT(_qe)
+#endif
+
+#define bfa_q_is_on_q(_q, _qe) \
+ bfa_q_is_on_q_func(_q, (struct list_head *)(_qe))
+extern int bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe);
+
+#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_sm.h b/drivers/scsi/bfa/include/cs/bfa_sm.h
new file mode 100644
index 000000000000..b0a92baf6657
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_sm.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfasm.h State machine defines
+ */
+
+#ifndef __BFA_SM_H__
+#define __BFA_SM_H__
+
+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_get_state(_sm) ((_sm)->sm)
+#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (bfa_sm_t)(_state))
+
+/**
+ * For converting from state machine function to state encoding.
+ */
+struct bfa_sm_table_s {
+ bfa_sm_t sm; /* state machine function */
+ int state; /* state machine encoding */
+ char *name; /* state name for display */
+};
+#define BFA_SM(_sm) ((bfa_sm_t)(_sm))
+
+int bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm);
+
+/**
+ * State machine with entry actions.
+ */
+typedef void (*bfa_fsm_t)(void *fsm, int event);
+
+/**
+ * oc - object class eg. bfa_ioc
+ * st - state, eg. reset
+ * otype - object type, eg. struct bfa_ioc_s
+ * etype - object type, eg. enum ioc_event
+ */
+#define bfa_fsm_state_decl(oc, st, otype, etype) \
+ static void oc ## _sm_ ## st(otype * fsm, etype event); \
+ static void oc ## _sm_ ## st ## _entry(otype * fsm)
+
+#define bfa_fsm_set_state(_fsm, _state) do { \
+ (_fsm)->fsm = (bfa_fsm_t)(_state); \
+ _state ## _entry(_fsm); \
+} while (0)
+
+#define bfa_fsm_send_event(_fsm, _event) \
+ ((_fsm)->fsm((_fsm), (_event)))
+#define bfa_fsm_cmp_state(_fsm, _state) \
+ ((_fsm)->fsm == (bfa_fsm_t)(_state))
+
+#endif
diff --git a/drivers/scsi/bfa/include/cs/bfa_trc.h b/drivers/scsi/bfa/include/cs/bfa_trc.h
new file mode 100644
index 000000000000..310771c888e7
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_trc.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_TRC_H__
+#define __BFA_TRC_H__
+
+#include <bfa_os_inc.h>
+
+#ifndef BFA_TRC_MAX
+#define BFA_TRC_MAX (4 * 1024)
+#endif
+
+#ifndef BFA_TRC_TS
+#define BFA_TRC_TS(_trcm) ((_trcm)->ticks++)
+#endif
+
+struct bfa_trc_s {
+#ifdef __BIGENDIAN
+ u16 fileno;
+ u16 line;
+#else
+ u16 line;
+ u16 fileno;
+#endif
+ u32 timestamp;
+ union {
+ struct {
+ u32 rsvd;
+ u32 u32;
+ } u32;
+ u64 u64;
+ } data;
+};
+
+
+struct bfa_trc_mod_s {
+ u32 head;
+ u32 tail;
+ u32 ntrc;
+ u32 stopped;
+ u32 ticks;
+ u32 rsvd[3];
+ struct bfa_trc_s trc[BFA_TRC_MAX];
+};
+
+
+enum {
+ BFA_TRC_FW = 1, /* firmware modules */
+ BFA_TRC_HAL = 2, /* BFA modules */
+ BFA_TRC_FCS = 3, /* BFA FCS modules */
+ BFA_TRC_LDRV = 4, /* Linux driver modules */
+ BFA_TRC_SDRV = 5, /* Solaris driver modules */
+ BFA_TRC_VDRV = 6, /* vmware driver modules */
+ BFA_TRC_WDRV = 7, /* windows driver modules */
+ BFA_TRC_AEN = 8, /* AEN module */
+ BFA_TRC_BIOS = 9, /* bios driver modules */
+ BFA_TRC_EFI = 10, /* EFI driver modules */
+ BNA_TRC_WDRV = 11, /* BNA windows driver modules */
+ BNA_TRC_VDRV = 12, /* BNA vmware driver modules */
+ BNA_TRC_SDRV = 13, /* BNA Solaris driver modules */
+ BNA_TRC_LDRV = 14, /* BNA Linux driver modules */
+ BNA_TRC_HAL = 15, /* BNA modules */
+ BFA_TRC_CNA = 16, /* Common modules */
+ BNA_TRC_IMDRV = 17 /* BNA windows intermediate driver modules */
+};
+#define BFA_TRC_MOD_SH 10
+#define BFA_TRC_MOD(__mod) ((BFA_TRC_ ## __mod) << BFA_TRC_MOD_SH)
+
+/**
+ * Define a new tracing file (module). Module should match one defined above.
+ */
+#define BFA_TRC_FILE(__mod, __submod) \
+ static int __trc_fileno = ((BFA_TRC_ ## __mod ## _ ## __submod) | \
+ BFA_TRC_MOD(__mod))
+
+
+#define bfa_trc32(_trcp, _data) \
+ __bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data)
+
+
+#ifndef BFA_BOOT_BUILD
+#define bfa_trc(_trcp, _data) \
+ __bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u64)_data)
+#else
+void bfa_boot_trc(struct bfa_trc_mod_s *trcmod, u16 fileno,
+ u16 line, u32 data);
+#define bfa_trc(_trcp, _data) \
+ bfa_boot_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data)
+#endif
+
+
+static inline void
+bfa_trc_init(struct bfa_trc_mod_s *trcm)
+{
+ trcm->head = trcm->tail = trcm->stopped = 0;
+ trcm->ntrc = BFA_TRC_MAX;
+}
+
+
+static inline void
+bfa_trc_stop(struct bfa_trc_mod_s *trcm)
+{
+ trcm->stopped = 1;
+}
+
+#ifdef FWTRC
+extern void dc_flush(void *data);
+#else
+#define dc_flush(data)
+#endif
+
+
+static inline void
+__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data)
+{
+ int tail = trcm->tail;
+ struct bfa_trc_s *trc = &trcm->trc[tail];
+
+ if (trcm->stopped)
+ return;
+
+ trc->fileno = (u16) fileno;
+ trc->line = (u16) line;
+ trc->data.u64 = data;
+ trc->timestamp = BFA_TRC_TS(trcm);
+ dc_flush(trc);
+
+ trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
+ if (trcm->tail == trcm->head)
+ trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
+ dc_flush(trcm);
+}
+
+
+static inline void
+__bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data)
+{
+ int tail = trcm->tail;
+ struct bfa_trc_s *trc = &trcm->trc[tail];
+
+ if (trcm->stopped)
+ return;
+
+ trc->fileno = (u16) fileno;
+ trc->line = (u16) line;
+ trc->data.u32.u32 = data;
+ trc->timestamp = BFA_TRC_TS(trcm);
+ dc_flush(trc);
+
+ trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1);
+ if (trcm->tail == trcm->head)
+ trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1);
+ dc_flush(trcm);
+}
+
+#ifndef BFA_PERF_BUILD
+#define bfa_trc_fp(_trcp, _data) bfa_trc(_trcp, _data)
+#else
+#define bfa_trc_fp(_trcp, _data)
+#endif
+
+#endif /* __BFA_TRC_H__ */
+
diff --git a/drivers/scsi/bfa/include/cs/bfa_wc.h b/drivers/scsi/bfa/include/cs/bfa_wc.h
new file mode 100644
index 000000000000..0460bd4fc7c4
--- /dev/null
+++ b/drivers/scsi/bfa/include/cs/bfa_wc.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_wc.h Generic wait counter.
+ */
+
+#ifndef __BFA_WC_H__
+#define __BFA_WC_H__
+
+typedef void (*bfa_wc_resume_t) (void *cbarg);
+
+struct bfa_wc_s {
+ bfa_wc_resume_t wc_resume;
+ void *wc_cbarg;
+ int wc_count;
+};
+
+static inline void
+bfa_wc_up(struct bfa_wc_s *wc)
+{
+ wc->wc_count++;
+}
+
+static inline void
+bfa_wc_down(struct bfa_wc_s *wc)
+{
+ wc->wc_count--;
+ if (wc->wc_count == 0)
+ wc->wc_resume(wc->wc_cbarg);
+}
+
+/**
+ * Initialize a waiting counter.
+ */
+static inline void
+bfa_wc_init(struct bfa_wc_s *wc, bfa_wc_resume_t wc_resume, void *wc_cbarg)
+{
+ wc->wc_resume = wc_resume;
+ wc->wc_cbarg = wc_cbarg;
+ wc->wc_count = 0;
+ bfa_wc_up(wc);
+}
+
+/**
+ * Wait for counter to reach zero
+ */
+static inline void
+bfa_wc_wait(struct bfa_wc_s *wc)
+{
+ bfa_wc_down(wc);
+}
+
+#endif
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h
new file mode 100644
index 000000000000..8c208fc8e329
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_adapter.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DEFS_ADAPTER_H__
+#define __BFA_DEFS_ADAPTER_H__
+
+#include <protocol/types.h>
+#include <defs/bfa_defs_version.h>
+#include <defs/bfa_defs_mfg.h>
+
+/**
+ * BFA adapter level attributes.
+ */
+enum {
+ BFA_ADAPTER_SERIAL_NUM_LEN = STRSZ(BFA_MFG_SERIALNUM_SIZE),
+ /*
+ *!< adapter serial num length
+ */
+ BFA_ADAPTER_MODEL_NAME_LEN = 16, /* model name length */
+ BFA_ADAPTER_MODEL_DESCR_LEN = 128, /* model description length */
+ BFA_ADAPTER_MFG_NAME_LEN = 8, /* manufacturer name length */
+ BFA_ADAPTER_SYM_NAME_LEN = 64, /* adapter symbolic name length */
+ BFA_ADAPTER_OS_TYPE_LEN = 64, /* adapter os type length */
+};
+
+struct bfa_adapter_attr_s {
+ char manufacturer[BFA_ADAPTER_MFG_NAME_LEN];
+ char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
+ u32 rsvd1;
+ char model[BFA_ADAPTER_MODEL_NAME_LEN];
+ char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN];
+ wwn_t pwwn;
+ char node_symname[FC_SYMNAME_MAX];
+ char hw_ver[BFA_VERSION_LEN];
+ char fw_ver[BFA_VERSION_LEN];
+ char optrom_ver[BFA_VERSION_LEN];
+ char os_type[BFA_ADAPTER_OS_TYPE_LEN];
+ struct bfa_mfg_vpd_s vpd;
+ struct mac_s mac;
+
+ u8 nports;
+ u8 max_speed;
+ u8 prototype;
+ char asic_rev;
+
+ u8 pcie_gen;
+ u8 pcie_lanes_orig;
+ u8 pcie_lanes;
+ u8 cna_capable;
+};
+
+/**
+ * BFA adapter level events
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_PORT_AEN_ADD: [in]: None [out]: serial_num, pwwn, nports
+ * BFA_PORT_AEN_REMOVE: [in]: pwwn [out]: serial_num, pwwn, nports
+ */
+enum bfa_adapter_aen_event {
+ BFA_ADAPTER_AEN_ADD = 1, /* New Adapter found event */
+ BFA_ADAPTER_AEN_REMOVE = 2, /* Adapter removed event */
+};
+
+struct bfa_adapter_aen_data_s {
+ char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN];
+ u32 nports; /* Number of NPorts */
+ wwn_t pwwn; /* WWN of one of its physical port */
+};
+
+#endif /* __BFA_DEFS_ADAPTER_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_aen.h b/drivers/scsi/bfa/include/defs/bfa_defs_aen.h
new file mode 100644
index 000000000000..4c81a613db3d
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_aen.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_AEN_H__
+#define __BFA_DEFS_AEN_H__
+
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_ioc.h>
+#include <defs/bfa_defs_adapter.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_lport.h>
+#include <defs/bfa_defs_rport.h>
+#include <defs/bfa_defs_itnim.h>
+#include <defs/bfa_defs_tin.h>
+#include <defs/bfa_defs_ipfc.h>
+#include <defs/bfa_defs_audit.h>
+#include <defs/bfa_defs_ethport.h>
+
+enum bfa_aen_category {
+ BFA_AEN_CAT_ADAPTER = 1,
+ BFA_AEN_CAT_PORT = 2,
+ BFA_AEN_CAT_LPORT = 3,
+ BFA_AEN_CAT_RPORT = 4,
+ BFA_AEN_CAT_ITNIM = 5,
+ BFA_AEN_CAT_TIN = 6,
+ BFA_AEN_CAT_IPFC = 7,
+ BFA_AEN_CAT_AUDIT = 8,
+ BFA_AEN_CAT_IOC = 9,
+ BFA_AEN_CAT_ETHPORT = 10,
+ BFA_AEN_MAX_CAT = 10
+};
+
+#pragma pack(1)
+union bfa_aen_data_u {
+ struct bfa_adapter_aen_data_s adapter;
+ struct bfa_port_aen_data_s port;
+ struct bfa_lport_aen_data_s lport;
+ struct bfa_rport_aen_data_s rport;
+ struct bfa_itnim_aen_data_s itnim;
+ struct bfa_audit_aen_data_s audit;
+ struct bfa_ioc_aen_data_s ioc;
+ struct bfa_ethport_aen_data_s ethport;
+};
+
+struct bfa_aen_entry_s {
+ enum bfa_aen_category aen_category;
+ int aen_type;
+ union bfa_aen_data_u aen_data;
+ struct bfa_timeval_s aen_tv;
+ s32 seq_num;
+ s32 bfad_num;
+ s32 rsvd[1];
+};
+
+#pragma pack()
+
+#define bfa_aen_event_t int
+
+#endif /* __BFA_DEFS_AEN_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_audit.h b/drivers/scsi/bfa/include/defs/bfa_defs_audit.h
new file mode 100644
index 000000000000..8e3a962bf20c
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_audit.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_AUDIT_H__
+#define __BFA_DEFS_AUDIT_H__
+
+#include <bfa_os_inc.h>
+
+/**
+ * BFA audit events
+ */
+enum bfa_audit_aen_event {
+ BFA_AUDIT_AEN_AUTH_ENABLE = 1,
+ BFA_AUDIT_AEN_AUTH_DISABLE = 2,
+};
+
+/**
+ * audit event data
+ */
+struct bfa_audit_aen_data_s {
+ wwn_t pwwn;
+};
+
+#endif /* __BFA_DEFS_AUDIT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_auth.h b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h
new file mode 100644
index 000000000000..dd19c83aba58
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_auth.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DEFS_AUTH_H__
+#define __BFA_DEFS_AUTH_H__
+
+#include <defs/bfa_defs_types.h>
+
+#define PUBLIC_KEY 15409
+#define PRIVATE_KEY 19009
+#define KEY_LEN 32399
+#define BFA_AUTH_SECRET_STRING_LEN 256
+#define BFA_AUTH_FAIL_TIMEOUT 0xFF
+
+/**
+ * Authentication status
+ */
+enum bfa_auth_status {
+ BFA_AUTH_STATUS_NONE = 0, /* no authentication */
+ BFA_AUTH_UNINIT = 1, /* state - uninit */
+ BFA_AUTH_NEG_SEND = 2, /* state - negotiate send */
+ BFA_AUTH_CHAL_WAIT = 3, /* state - challenge wait */
+ BFA_AUTH_NEG_RETRY = 4, /* state - negotiate retry */
+ BFA_AUTH_REPLY_SEND = 5, /* state - reply send */
+ BFA_AUTH_STATUS_WAIT = 6, /* state - status wait */
+ BFA_AUTH_SUCCESS = 7, /* state - success */
+ BFA_AUTH_FAILED = 8, /* state - failed */
+ BFA_AUTH_STATUS_UNKNOWN = 9, /* authentication status unknown */
+};
+
+struct auth_proto_stats_s {
+ u32 auth_rjts;
+ u32 auth_negs;
+ u32 auth_dones;
+
+ u32 dhchap_challenges;
+ u32 dhchap_replies;
+ u32 dhchap_successes;
+};
+
+/**
+ * Authentication related statistics
+ */
+struct bfa_auth_stats_s {
+ u32 auth_failures; /* authentication failures */
+ u32 auth_successes; /* authentication successes*/
+ struct auth_proto_stats_s auth_rx_stats; /* Rx protocol stats */
+ struct auth_proto_stats_s auth_tx_stats; /* Tx protocol stats */
+};
+
+/**
+ * Authentication hash function algorithms
+ */
+enum bfa_auth_algo {
+ BFA_AUTH_ALGO_MD5 = 1, /* Message-Digest algorithm 5 */
+ BFA_AUTH_ALGO_SHA1 = 2, /* Secure Hash Algorithm 1 */
+ BFA_AUTH_ALGO_MS = 3, /* MD5, then SHA-1 */
+ BFA_AUTH_ALGO_SM = 4, /* SHA-1, then MD5 */
+};
+
+/**
+ * DH Groups
+ *
+ * Current value could be combination of one or more of the following values
+ */
+enum bfa_auth_group {
+ BFA_AUTH_GROUP_DHNULL = 0, /* DH NULL (value == 0) */
+ BFA_AUTH_GROUP_DH768 = 1, /* DH group 768 (value == 1) */
+ BFA_AUTH_GROUP_DH1024 = 2, /* DH group 1024 (value == 2) */
+ BFA_AUTH_GROUP_DH1280 = 4, /* DH group 1280 (value == 3) */
+ BFA_AUTH_GROUP_DH1536 = 8, /* DH group 1536 (value == 4) */
+
+ BFA_AUTH_GROUP_ALL = 256 /* Use default DH group order
+ * 0, 1, 2, 3, 4 */
+};
+
+/**
+ * Authentication secret sources
+ */
+enum bfa_auth_secretsource {
+ BFA_AUTH_SECSRC_LOCAL = 1, /* locally configured */
+ BFA_AUTH_SECSRC_RADIUS = 2, /* use radius server */
+ BFA_AUTH_SECSRC_TACACS = 3, /* TACACS server */
+};
+
+/**
+ * Authentication attributes
+ */
+struct bfa_auth_attr_s {
+ enum bfa_auth_status status;
+ enum bfa_auth_algo algo;
+ enum bfa_auth_group dh_grp;
+ u16 rjt_code;
+ u16 rjt_code_exp;
+ u8 secret_set;
+ u8 resv[7];
+};
+
+#endif /* __BFA_DEFS_AUTH_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_boot.h b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h
new file mode 100644
index 000000000000..6f4aa5283545
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_boot.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_BOOT_H__
+#define __BFA_DEFS_BOOT_H__
+
+#include <protocol/types.h>
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_pport.h>
+
+enum {
+ BFA_BOOT_BOOTLUN_MAX = 4, /* maximum boot lun per IOC */
+};
+
+#define BOOT_CFG_REV1 1
+
+/**
+ * Boot options setting. Boot options setting determines from where
+ * to get the boot lun information
+ */
+enum bfa_boot_bootopt {
+ BFA_BOOT_AUTO_DISCOVER = 0, /* Boot from blun provided by fabric */
+ BFA_BOOT_STORED_BLUN = 1, /* Boot from bluns stored in flash */
+ BFA_BOOT_FIRST_LUN = 2, /* Boot from first discovered blun */
+};
+
+/**
+ * Boot lun information.
+ */
+struct bfa_boot_bootlun_s {
+ wwn_t pwwn; /* port wwn of target */
+ lun_t lun; /* 64-bit lun */
+};
+
+/**
+ * BOOT boot configuraton
+ */
+struct bfa_boot_cfg_s {
+ u8 version;
+ u8 rsvd1;
+ u16 chksum;
+
+ u8 enable; /* enable/disable SAN boot */
+ u8 speed; /* boot speed settings */
+ u8 topology; /* boot topology setting */
+ u8 bootopt; /* bfa_boot_bootopt_t */
+
+ u32 nbluns; /* number of boot luns */
+
+ u32 rsvd2;
+
+ struct bfa_boot_bootlun_s blun[BFA_BOOT_BOOTLUN_MAX];
+ struct bfa_boot_bootlun_s blun_disc[BFA_BOOT_BOOTLUN_MAX];
+};
+
+
+#endif /* __BFA_DEFS_BOOT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_cee.h b/drivers/scsi/bfa/include/defs/bfa_defs_cee.h
new file mode 100644
index 000000000000..520a22f52dd1
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_cee.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * bfa_defs_cee.h Interface declarations between host based
+ * BFAL and DCBX/LLDP module in Firmware
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DEFS_CEE_H__
+#define __BFA_DEFS_CEE_H__
+
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_pport.h>
+#include <protocol/types.h>
+
+#pragma pack(1)
+
+#define BFA_CEE_LLDP_MAX_STRING_LEN (128)
+
+
+/* FIXME: this is coming from the protocol spec. Can the host & apps share the
+ protocol .h files ?
+ */
+#define BFA_CEE_LLDP_SYS_CAP_OTHER 0x0001
+#define BFA_CEE_LLDP_SYS_CAP_REPEATER 0x0002
+#define BFA_CEE_LLDP_SYS_CAP_MAC_BRIDGE 0x0004
+#define BFA_CEE_LLDP_SYS_CAP_WLAN_AP 0x0008
+#define BFA_CEE_LLDP_SYS_CAP_ROUTER 0x0010
+#define BFA_CEE_LLDP_SYS_CAP_TELEPHONE 0x0020
+#define BFA_CEE_LLDP_SYS_CAP_DOCSIS_CD 0x0040
+#define BFA_CEE_LLDP_SYS_CAP_STATION 0x0080
+#define BFA_CEE_LLDP_SYS_CAP_CVLAN 0x0100
+#define BFA_CEE_LLDP_SYS_CAP_SVLAN 0x0200
+#define BFA_CEE_LLDP_SYS_CAP_TPMR 0x0400
+
+
+/* LLDP string type */
+struct bfa_cee_lldp_str_s {
+ u8 sub_type;
+ u8 len;
+ u8 rsvd[2];
+ u8 value[BFA_CEE_LLDP_MAX_STRING_LEN];
+};
+
+
+/* LLDP paramters */
+struct bfa_cee_lldp_cfg_s {
+ struct bfa_cee_lldp_str_s chassis_id;
+ struct bfa_cee_lldp_str_s port_id;
+ struct bfa_cee_lldp_str_s port_desc;
+ struct bfa_cee_lldp_str_s sys_name;
+ struct bfa_cee_lldp_str_s sys_desc;
+ struct bfa_cee_lldp_str_s mgmt_addr;
+ u16 time_to_interval;
+ u16 enabled_system_cap;
+};
+
+enum bfa_cee_dcbx_version_e {
+ DCBX_PROTOCOL_PRECEE = 1,
+ DCBX_PROTOCOL_CEE = 2,
+};
+
+enum bfa_cee_lls_e {
+ CEE_LLS_DOWN_NO_TLV = 0, /* LLS is down because the TLV not sent by
+ * the peer */
+ CEE_LLS_DOWN = 1, /* LLS is down as advertised by the peer */
+ CEE_LLS_UP = 2,
+};
+
+/* CEE/DCBX parameters */
+struct bfa_cee_dcbx_cfg_s {
+ u8 pgid[8];
+ u8 pg_percentage[8];
+ u8 pfc_enabled; /* bitmap of priorties with PFC enabled */
+ u8 fcoe_user_priority; /* bitmap of priorities used for FcoE
+ * traffic */
+ u8 dcbx_version; /* operating version:CEE or preCEE */
+ u8 lls_fcoe; /* FCoE Logical Link Status */
+ u8 lls_lan; /* LAN Logical Link Status */
+ u8 rsvd[3];
+};
+
+/* CEE status */
+/* Making this to tri-state for the benefit of port list command */
+enum bfa_cee_status_e {
+ CEE_PHY_DOWN = 0,
+ CEE_PHY_UP = 1,
+ CEE_UP = 2,
+};
+
+/* CEE Query */
+struct bfa_cee_attr_s {
+ u8 cee_status;
+ u8 error_reason;
+ struct bfa_cee_lldp_cfg_s lldp_remote;
+ struct bfa_cee_dcbx_cfg_s dcbx_remote;
+ mac_t src_mac;
+ u8 link_speed;
+ u8 filler[3];
+};
+
+
+
+
+/* LLDP/DCBX/CEE Statistics */
+
+struct bfa_cee_lldp_stats_s {
+ u32 frames_transmitted;
+ u32 frames_aged_out;
+ u32 frames_discarded;
+ u32 frames_in_error;
+ u32 frames_rcvd;
+ u32 tlvs_discarded;
+ u32 tlvs_unrecognized;
+};
+
+struct bfa_cee_dcbx_stats_s {
+ u32 subtlvs_unrecognized;
+ u32 negotiation_failed;
+ u32 remote_cfg_changed;
+ u32 tlvs_received;
+ u32 tlvs_invalid;
+ u32 seqno;
+ u32 ackno;
+ u32 recvd_seqno;
+ u32 recvd_ackno;
+};
+
+struct bfa_cee_cfg_stats_s {
+ u32 cee_status_down;
+ u32 cee_status_up;
+ u32 cee_hw_cfg_changed;
+ u32 recvd_invalid_cfg;
+};
+
+
+struct bfa_cee_stats_s {
+ struct bfa_cee_lldp_stats_s lldp_stats;
+ struct bfa_cee_dcbx_stats_s dcbx_stats;
+ struct bfa_cee_cfg_stats_s cfg_stats;
+};
+
+#pragma pack()
+
+
+#endif /* __BFA_DEFS_CEE_H__ */
+
+
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_driver.h b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h
new file mode 100644
index 000000000000..57049805762b
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_driver.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_DRIVER_H__
+#define __BFA_DEFS_DRIVER_H__
+
+/**
+ * Driver statistics
+ */
+ u16 tm_io_abort;
+ u16 tm_io_abort_comp;
+ u16 tm_lun_reset;
+ u16 tm_lun_reset_comp;
+ u16 tm_target_reset;
+ u16 tm_bus_reset;
+ u16 ioc_restart; /* IOC restart count */
+ u16 io_pending; /* outstanding io count per-IOC */
+ u64 control_req;
+ u64 input_req;
+ u64 output_req;
+ u64 input_words;
+ u64 output_words;
+} bfa_driver_stats_t;
+
+
+#endif /* __BFA_DEFS_DRIVER_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h b/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h
new file mode 100644
index 000000000000..79f9b3e146f7
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_ethport.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_ETHPORT_H__
+#define __BFA_DEFS_ETHPORT_H__
+
+#include <defs/bfa_defs_status.h>
+#include <protocol/types.h>
+#include <cna/pstats/phyport_defs.h>
+#include <cna/pstats/ethport_defs.h>
+
+struct bna_tx_info_s {
+ u32 miniport_state;
+ u32 adapter_state;
+ u64 tx_count;
+ u64 tx_wi;
+ u64 tx_sg;
+ u64 tx_tcp_chksum;
+ u64 tx_udp_chksum;
+ u64 tx_ip_chksum;
+ u64 tx_lsov1;
+ u64 tx_lsov2;
+ u64 tx_max_sg_len ;
+};
+
+struct bna_rx_queue_info_s {
+ u16 q_id ;
+ u16 buf_size ;
+ u16 buf_count ;
+ u16 rsvd ;
+ u64 rx_count ;
+ u64 rx_dropped ;
+ u64 rx_unsupported ;
+ u64 rx_internal_err ;
+ u64 rss_count ;
+ u64 vlan_count ;
+ u64 rx_tcp_chksum ;
+ u64 rx_udp_chksum ;
+ u64 rx_ip_chksum ;
+ u64 rx_hds ;
+};
+
+struct bna_rx_q_set_s {
+ u16 q_set_type;
+ u32 miniport_state;
+ u32 adapter_state;
+ struct bna_rx_queue_info_s rx_queue[2];
+};
+
+struct bna_port_stats_s {
+ struct bna_tx_info_s tx_stats;
+ u16 qset_count ;
+ struct bna_rx_q_set_s rx_qset[8];
+};
+
+struct bfa_ethport_stats_s {
+ struct bna_stats_txf txf_stats[1];
+ struct bna_stats_rxf rxf_stats[1];
+ struct bnad_drv_stats drv_stats;
+};
+
+/**
+ * Ethernet port events
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_PORT_AEN_ETH_LINKUP: [in]: mac [out]: mac
+ * BFA_PORT_AEN_ETH_LINKDOWN: [in]: mac [out]: mac
+ * BFA_PORT_AEN_ETH_ENABLE: [in]: mac [out]: mac
+ * BFA_PORT_AEN_ETH_DISABLE: [in]: mac [out]: mac
+ *
+ */
+enum bfa_ethport_aen_event {
+ BFA_ETHPORT_AEN_LINKUP = 1, /* Base Port Ethernet link up event */
+ BFA_ETHPORT_AEN_LINKDOWN = 2, /* Base Port Ethernet link down event */
+ BFA_ETHPORT_AEN_ENABLE = 3, /* Base Port Ethernet link enable event */
+ BFA_ETHPORT_AEN_DISABLE = 4, /* Base Port Ethernet link disable
+ * event */
+};
+
+struct bfa_ethport_aen_data_s {
+ mac_t mac; /* MAC address of the physical port */
+};
+
+
+#endif /* __BFA_DEFS_ETHPORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h b/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h
new file mode 100644
index 000000000000..c08f4f5026ac
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_fcpim.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DEFS_FCPIM_H__
+#define __BFA_DEFS_FCPIM_H__
+
+struct bfa_fcpim_stats_s {
+ u32 total_ios; /* Total IO count */
+ u32 qresumes; /* IO waiting for CQ space */
+ u32 no_iotags; /* NO IO contexts */
+ u32 io_aborts; /* IO abort requests */
+ u32 no_tskims; /* NO task management contexts */
+ u32 iocomp_ok; /* IO completions with OK status */
+ u32 iocomp_underrun; /* IO underrun (good) */
+ u32 iocomp_overrun; /* IO overrun (good) */
+ u32 iocomp_aborted; /* Aborted IO requests */
+ u32 iocomp_timedout; /* IO timeouts */
+ u32 iocom_nexus_abort; /* IO selection timeouts */
+ u32 iocom_proto_err; /* IO protocol errors */
+ u32 iocom_dif_err; /* IO SBC-3 protection errors */
+ u32 iocom_tm_abort; /* IO aborted by TM requests */
+ u32 iocom_sqer_needed; /* IO retry for SQ error
+ *recovery */
+ u32 iocom_res_free; /* Delayed freeing of IO resources */
+ u32 iocomp_scsierr; /* IO with non-good SCSI status */
+ u32 iocom_hostabrts; /* Host IO abort requests */
+ u32 iocom_utags; /* IO comp with unknown tags */
+ u32 io_cleanups; /* IO implicitly aborted */
+ u32 io_tmaborts; /* IO aborted due to TM commands */
+ u32 rsvd;
+};
+#endif /*__BFA_DEFS_FCPIM_H__*/
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_im_common.h b/drivers/scsi/bfa/include/defs/bfa_defs_im_common.h
new file mode 100644
index 000000000000..9ccf53bef65a
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_im_common.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_IM_COMMON_H__
+#define __BFA_DEFS_IM_COMMON_H__
+
+#define BFA_ADAPTER_NAME_LEN 256
+#define BFA_ADAPTER_GUID_LEN 256
+#define RESERVED_VLAN_NAME L"PORT VLAN"
+#define PASSTHRU_VLAN_NAME L"PASSTHRU VLAN"
+
+ u64 tx_pkt_cnt;
+ u64 rx_pkt_cnt;
+ u32 duration;
+ u8 status;
+} bfa_im_stats_t, *pbfa_im_stats_t;
+
+#endif /* __BFA_DEFS_IM_COMMON_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_im_team.h b/drivers/scsi/bfa/include/defs/bfa_defs_im_team.h
new file mode 100644
index 000000000000..a486a7eb81d6
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_im_team.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_IM_TEAM_H__
+#define __BFA_DEFS_IM_TEAM_H__
+
+#include <protocol/types.h>
+
+#define BFA_TEAM_MAX_PORTS 8
+#define BFA_TEAM_NAME_LEN 256
+#define BFA_MAX_NUM_TEAMS 16
+#define BFA_TEAM_INVALID_DELAY -1
+
+ BFA_LACP_RATE_SLOW = 1,
+ BFA_LACP_RATE_FAST
+} bfa_im_lacp_rate_t;
+
+ BFA_TEAM_MODE_FAIL_OVER = 1,
+ BFA_TEAM_MODE_FAIL_BACK,
+ BFA_TEAM_MODE_LACP,
+ BFA_TEAM_MODE_NONE
+} bfa_im_team_mode_t;
+
+ BFA_XMIT_POLICY_L2 = 1,
+ BFA_XMIT_POLICY_L3_L4
+} bfa_im_xmit_policy_t;
+
+ bfa_im_team_mode_t team_mode;
+ bfa_im_lacp_rate_t lacp_rate;
+ bfa_im_xmit_policy_t xmit_policy;
+ int delay;
+ wchar_t primary[BFA_ADAPTER_NAME_LEN];
+ wchar_t preferred_primary[BFA_ADAPTER_NAME_LEN];
+ mac_t mac;
+ u16 num_ports;
+ u16 num_vlans;
+ u16 vlan_list[BFA_MAX_VLANS_PER_PORT];
+ wchar_t team_guid_list[BFA_TEAM_MAX_PORTS][BFA_ADAPTER_GUID_LEN];
+ wchar_t ioc_name_list[BFA_TEAM_MAX_PORTS][BFA_ADAPTER_NAME_LEN];
+} bfa_im_team_attr_t;
+
+ wchar_t team_name[BFA_TEAM_NAME_LEN];
+ bfa_im_xmit_policy_t xmit_policy;
+ int delay;
+ wchar_t primary[BFA_ADAPTER_NAME_LEN];
+ wchar_t preferred_primary[BFA_ADAPTER_NAME_LEN];
+} bfa_im_team_edit_t, *pbfa_im_team_edit_t;
+
+ wchar_t team_name[BFA_TEAM_NAME_LEN];
+ bfa_im_team_mode_t team_mode;
+ mac_t mac;
+} bfa_im_team_info_t;
+
+ bfa_im_team_info_t team_info[BFA_MAX_NUM_TEAMS];
+ u16 num_teams;
+} bfa_im_team_list_t, *pbfa_im_team_list_t;
+
+#endif /* __BFA_DEFS_IM_TEAM_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h
new file mode 100644
index 000000000000..b1d532da3a9d
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_ioc.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_IOC_H__
+#define __BFA_DEFS_IOC_H__
+
+#include <protocol/types.h>
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_version.h>
+#include <defs/bfa_defs_adapter.h>
+#include <defs/bfa_defs_pm.h>
+
+enum {
+ BFA_IOC_DRIVER_LEN = 16,
+ BFA_IOC_CHIP_REV_LEN = 8,
+};
+
+/**
+ * Driver and firmware versions.
+ */
+struct bfa_ioc_driver_attr_s {
+ char driver[BFA_IOC_DRIVER_LEN]; /* driver name */
+ char driver_ver[BFA_VERSION_LEN]; /* driver version */
+ char fw_ver[BFA_VERSION_LEN]; /* firmware version*/
+ char bios_ver[BFA_VERSION_LEN]; /* bios version */
+ char efi_ver[BFA_VERSION_LEN]; /* EFI version */
+ char ob_ver[BFA_VERSION_LEN]; /* openboot version*/
+};
+
+/**
+ * IOC PCI device attributes
+ */
+struct bfa_ioc_pci_attr_s {
+ u16 vendor_id; /* PCI vendor ID */
+ u16 device_id; /* PCI device ID */
+ u16 ssid; /* subsystem ID */
+ u16 ssvid; /* subsystem vendor ID */
+ u32 pcifn; /* PCI device function */
+ u32 rsvd; /* padding */
+ u8 chip_rev[BFA_IOC_CHIP_REV_LEN]; /* chip revision */
+};
+
+/**
+ * IOC states
+ */
+enum bfa_ioc_state {
+ BFA_IOC_RESET = 1, /* IOC is in reset state */
+ BFA_IOC_SEMWAIT = 2, /* Waiting for IOC hardware semaphore */
+ BFA_IOC_HWINIT = 3, /* IOC hardware is being initialized */
+ BFA_IOC_GETATTR = 4, /* IOC is being configured */
+ BFA_IOC_OPERATIONAL = 5, /* IOC is operational */
+ BFA_IOC_INITFAIL = 6, /* IOC hardware failure */
+ BFA_IOC_HBFAIL = 7, /* IOC heart-beat failure */
+ BFA_IOC_DISABLING = 8, /* IOC is being disabled */
+ BFA_IOC_DISABLED = 9, /* IOC is disabled */
+ BFA_IOC_FWMISMATCH = 10, /* IOC firmware different from drivers */
+};
+
+/**
+ * IOC firmware stats
+ */
+struct bfa_fw_ioc_stats_s {
+ u32 hb_count;
+ u32 cfg_reqs;
+ u32 enable_reqs;
+ u32 disable_reqs;
+ u32 stats_reqs;
+ u32 clrstats_reqs;
+ u32 unknown_reqs;
+ u32 ic_reqs; /* interrupt coalesce reqs */
+};
+
+/**
+ * IOC driver stats
+ */
+struct bfa_ioc_drv_stats_s {
+ u32 ioc_isrs;
+ u32 ioc_enables;
+ u32 ioc_disables;
+ u32 ioc_hbfails;
+ u32 ioc_boots;
+ u32 stats_tmos;
+ u32 hb_count;
+ u32 disable_reqs;
+ u32 enable_reqs;
+ u32 disable_replies;
+ u32 enable_replies;
+};
+
+/**
+ * IOC statistics
+ */
+struct bfa_ioc_stats_s {
+ struct bfa_ioc_drv_stats_s drv_stats; /* driver IOC stats */
+ struct bfa_fw_ioc_stats_s fw_stats; /* firmware IOC stats */
+};
+
+
+enum bfa_ioc_type_e {
+ BFA_IOC_TYPE_FC = 1,
+ BFA_IOC_TYPE_FCoE = 2,
+ BFA_IOC_TYPE_LL = 3,
+};
+
+/**
+ * IOC attributes returned in queries
+ */
+struct bfa_ioc_attr_s {
+ enum bfa_ioc_type_e ioc_type;
+ enum bfa_ioc_state state; /* IOC state */
+ struct bfa_adapter_attr_s adapter_attr; /* HBA attributes */
+ struct bfa_ioc_driver_attr_s driver_attr; /* driver attr */
+ struct bfa_ioc_pci_attr_s pci_attr;
+ u8 port_id; /* port number */
+};
+
+/**
+ * BFA IOC level events
+ */
+enum bfa_ioc_aen_event {
+ BFA_IOC_AEN_HBGOOD = 1, /* Heart Beat restore event */
+ BFA_IOC_AEN_HBFAIL = 2, /* Heart Beat failure event */
+ BFA_IOC_AEN_ENABLE = 3, /* IOC enabled event */
+ BFA_IOC_AEN_DISABLE = 4, /* IOC disabled event */
+ BFA_IOC_AEN_FWMISMATCH = 5, /* IOC firmware mismatch */
+};
+
+/**
+ * BFA IOC level event data, now just a place holder
+ */
+struct bfa_ioc_aen_data_s {
+ enum bfa_ioc_type_e ioc_type;
+ wwn_t pwwn;
+ mac_t mac;
+};
+
+#endif /* __BFA_DEFS_IOC_H__ */
+
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h
new file mode 100644
index 000000000000..d76bcbd9820f
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_iocfc.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_IOCFC_H__
+#define __BFA_DEFS_IOCFC_H__
+
+#include <protocol/types.h>
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_version.h>
+#include <defs/bfa_defs_adapter.h>
+#include <defs/bfa_defs_pm.h>
+
+#define BFA_IOCFC_INTR_DELAY 1125
+#define BFA_IOCFC_INTR_LATENCY 225
+
+/**
+ * Interrupt coalescing configuration.
+ */
+struct bfa_iocfc_intr_attr_s {
+ bfa_boolean_t coalesce; /* enable/disable coalescing */
+ u16 latency; /* latency in microseconds */
+ u16 delay; /* delay in microseconds */
+};
+
+/**
+ * IOC firmware configuraton
+ */
+struct bfa_iocfc_fwcfg_s {
+ u16 num_fabrics; /* number of fabrics */
+ u16 num_lports; /* number of local lports */
+ u16 num_rports; /* number of remote ports */
+ u16 num_ioim_reqs; /* number of IO reqs */
+ u16 num_tskim_reqs; /* task management requests */
+ u16 num_iotm_reqs; /* number of TM IO reqs */
+ u16 num_tsktm_reqs; /* TM task management requests*/
+ u16 num_fcxp_reqs; /* unassisted FC exchanges */
+ u16 num_uf_bufs; /* unsolicited recv buffers */
+ u8 num_cqs;
+ u8 rsvd;
+};
+
+struct bfa_iocfc_drvcfg_s {
+ u16 num_reqq_elems; /* number of req queue elements */
+ u16 num_rspq_elems; /* number of rsp queue elements */
+ u16 num_sgpgs; /* number of total SG pages */
+ u16 num_sboot_tgts; /* number of SAN boot targets */
+ u16 num_sboot_luns; /* number of SAN boot luns */
+ u16 ioc_recover; /* IOC recovery mode */
+ u16 min_cfg; /* minimum configuration */
+ u16 path_tov; /* device path timeout */
+ bfa_boolean_t delay_comp; /* delay completion of
+ failed inflight IOs */
+ u32 rsvd;
+};
+/**
+ * IOC configuration
+ */
+struct bfa_iocfc_cfg_s {
+ struct bfa_iocfc_fwcfg_s fwcfg; /* firmware side config */
+ struct bfa_iocfc_drvcfg_s drvcfg; /* driver side config */
+};
+
+/**
+ * IOC firmware IO stats
+ */
+struct bfa_fw_io_stats_s {
+ u32 host_abort; /* IO aborted by host driver*/
+ u32 host_cleanup; /* IO clean up by host driver */
+
+ u32 fw_io_timeout; /* IOs timedout */
+ u32 fw_frm_parse; /* frame parsed by f/w */
+ u32 fw_frm_data; /* fcp_data frame parsed by f/w */
+ u32 fw_frm_rsp; /* fcp_rsp frame parsed by f/w */
+ u32 fw_frm_xfer_rdy; /* xfer_rdy frame parsed by f/w */
+ u32 fw_frm_bls_acc; /* BLS ACC frame parsed by f/w */
+ u32 fw_frm_tgt_abort; /* target ABTS parsed by f/w */
+ u32 fw_frm_unknown; /* unknown parsed by f/w */
+ u32 fw_data_dma; /* f/w DMA'ed the data frame */
+ u32 fw_frm_drop; /* f/w drop the frame */
+
+ u32 rec_timeout; /* FW rec timed out */
+ u32 error_rec; /* FW sending rec on
+ * an error condition*/
+ u32 wait_for_si; /* FW wait for SI */
+ u32 rec_rsp_inval; /* REC rsp invalid */
+ u32 seqr_io_abort; /* target does not know cmd so abort */
+ u32 seqr_io_retry; /* SEQR failed so retry IO */
+
+ u32 itn_cisc_upd_rsp; /* ITN cisc updated on fcp_rsp */
+ u32 itn_cisc_upd_data; /* ITN cisc updated on fcp_data */
+ u32 itn_cisc_upd_xfer_rdy; /* ITN cisc updated on fcp_data */
+
+ u32 fcp_data_lost; /* fcp data lost */
+
+ u32 ro_set_in_xfer_rdy; /* Target set RO in Xfer_rdy frame */
+ u32 xfer_rdy_ooo_err; /* Out of order Xfer_rdy received */
+ u32 xfer_rdy_unknown_err; /* unknown error in xfer_rdy frame */
+
+ u32 io_abort_timeout; /* ABTS timedout */
+ u32 sler_initiated; /* SLER initiated */
+
+ u32 unexp_fcp_rsp; /* fcp response in wrong state */
+
+ u32 fcp_rsp_under_run; /* fcp rsp IO underrun */
+ u32 fcp_rsp_under_run_wr; /* fcp rsp IO underrun for write */
+ u32 fcp_rsp_under_run_err; /* fcp rsp IO underrun error */
+ u32 fcp_rsp_resid_inval; /* invalid residue */
+ u32 fcp_rsp_over_run; /* fcp rsp IO overrun */
+ u32 fcp_rsp_over_run_err; /* fcp rsp IO overrun error */
+ u32 fcp_rsp_proto_err; /* protocol error in fcp rsp */
+ u32 fcp_rsp_sense_err; /* error in sense info in fcp rsp */
+ u32 fcp_conf_req; /* FCP conf requested */
+
+ u32 tgt_aborted_io; /* target initiated abort */
+
+ u32 ioh_edtov_timeout_event;/* IOH edtov timer popped */
+ u32 ioh_fcp_rsp_excp_event; /* IOH FCP_RSP exception */
+ u32 ioh_fcp_conf_event; /* IOH FCP_CONF */
+ u32 ioh_mult_frm_rsp_event; /* IOH multi_frame FCP_RSP */
+ u32 ioh_hit_class2_event; /* IOH hit class2 */
+ u32 ioh_miss_other_event; /* IOH miss other */
+ u32 ioh_seq_cnt_err_event; /* IOH seq cnt error */
+ u32 ioh_len_err_event; /* IOH len error - fcp_dl !=
+ * bytes xfered */
+ u32 ioh_seq_len_err_event; /* IOH seq len error */
+ u32 ioh_data_oor_event; /* Data out of range */
+ u32 ioh_ro_ooo_event; /* Relative offset out of range */
+ u32 ioh_cpu_owned_event; /* IOH hit -iost owned by f/w */
+ u32 ioh_unexp_frame_event; /* unexpected frame recieved
+ * count */
+ u32 ioh_err_int; /* IOH error int during data-phase
+ * for scsi write
+ */
+};
+
+/**
+ * IOC port firmware stats
+ */
+
+struct bfa_fw_port_fpg_stats_s {
+ u32 intr_evt;
+ u32 intr;
+ u32 intr_excess;
+ u32 intr_cause0;
+ u32 intr_other;
+ u32 intr_other_ign;
+ u32 sig_lost;
+ u32 sig_regained;
+ u32 sync_lost;
+ u32 sync_to;
+ u32 sync_regained;
+ u32 div2_overflow;
+ u32 div2_underflow;
+ u32 efifo_overflow;
+ u32 efifo_underflow;
+ u32 idle_rx;
+ u32 lrr_rx;
+ u32 lr_rx;
+ u32 ols_rx;
+ u32 nos_rx;
+ u32 lip_rx;
+ u32 arbf0_rx;
+ u32 mrk_rx;
+ u32 const_mrk_rx;
+ u32 prim_unknown;
+ u32 rsvd;
+};
+
+
+struct bfa_fw_port_lksm_stats_s {
+ u32 hwsm_success; /* hwsm state machine success */
+ u32 hwsm_fails; /* hwsm fails */
+ u32 hwsm_wdtov; /* hwsm timed out */
+ u32 swsm_success; /* swsm success */
+ u32 swsm_fails; /* swsm fails */
+ u32 swsm_wdtov; /* swsm timed out */
+ u32 busybufs; /* link init failed due to busybuf */
+ u32 buf_waits; /* bufwait state entries */
+ u32 link_fails; /* link failures */
+ u32 psp_errors; /* primitive sequence protocol errors */
+ u32 lr_unexp; /* No. of times LR rx-ed unexpectedly */
+ u32 lrr_unexp; /* No. of times LRR rx-ed unexpectedly */
+ u32 lr_tx; /* No. of times LR tx started */
+ u32 lrr_tx; /* No. of times LRR tx started */
+ u32 ols_tx; /* No. of times OLS tx started */
+ u32 nos_tx; /* No. of times NOS tx started */
+};
+
+
+struct bfa_fw_port_snsm_stats_s {
+ u32 hwsm_success; /* Successful hwsm terminations */
+ u32 hwsm_fails; /* hwsm fail count */
+ u32 hwsm_wdtov; /* hwsm timed out */
+ u32 swsm_success; /* swsm success */
+ u32 swsm_wdtov; /* swsm timed out */
+ u32 error_resets; /* error resets initiated by upsm */
+ u32 sync_lost; /* Sync loss count */
+ u32 sig_lost; /* Signal loss count */
+};
+
+
+struct bfa_fw_port_physm_stats_s {
+ u32 module_inserts; /* Module insert count */
+ u32 module_xtracts; /* Module extracts count */
+ u32 module_invalids; /* Invalid module inserted count */
+ u32 module_read_ign; /* Module validation status ignored */
+ u32 laser_faults; /* Laser fault count */
+ u32 rsvd;
+};
+
+
+struct bfa_fw_fip_stats_s {
+ u32 disc_req; /* Discovery solicit requests */
+ u32 disc_rsp; /* Discovery solicit response */
+ u32 disc_err; /* Discovery advt. parse errors */
+ u32 disc_unsol; /* Discovery unsolicited */
+ u32 disc_timeouts; /* Discovery timeouts */
+ u32 linksvc_unsupp; /* Unsupported link service req */
+ u32 linksvc_err; /* Parse error in link service req */
+ u32 logo_req; /* Number of FIP logos received */
+ u32 clrvlink_req; /* Clear virtual link req */
+ u32 op_unsupp; /* Unsupported FIP operation */
+ u32 untagged; /* Untagged frames (ignored) */
+ u32 rsvd;
+};
+
+
+struct bfa_fw_lps_stats_s {
+ u32 mac_invalids; /* Invalid mac assigned */
+ u32 rsvd;
+};
+
+
+struct bfa_fw_fcoe_stats_s {
+ u32 cee_linkups; /* CEE link up count */
+ u32 cee_linkdns; /* CEE link down count */
+ u32 fip_linkups; /* FIP link up count */
+ u32 fip_linkdns; /* FIP link up count */
+ u32 fip_fails; /* FIP fail count */
+ u32 mac_invalids; /* Invalid mac assigned */
+};
+
+/**
+ * IOC firmware FCoE port stats
+ */
+struct bfa_fw_fcoe_port_stats_s {
+ struct bfa_fw_fcoe_stats_s fcoe_stats;
+ struct bfa_fw_fip_stats_s fip_stats;
+};
+
+/**
+ * IOC firmware FC port stats
+ */
+struct bfa_fw_fc_port_stats_s {
+ struct bfa_fw_port_fpg_stats_s fpg_stats;
+ struct bfa_fw_port_physm_stats_s physm_stats;
+ struct bfa_fw_port_snsm_stats_s snsm_stats;
+ struct bfa_fw_port_lksm_stats_s lksm_stats;
+};
+
+/**
+ * IOC firmware FC port stats
+ */
+union bfa_fw_port_stats_s {
+ struct bfa_fw_fc_port_stats_s fc_stats;
+ struct bfa_fw_fcoe_port_stats_s fcoe_stats;
+};
+
+/**
+ * IOC firmware stats
+ */
+struct bfa_fw_stats_s {
+ struct bfa_fw_ioc_stats_s ioc_stats;
+ struct bfa_fw_io_stats_s io_stats;
+ union bfa_fw_port_stats_s port_stats;
+};
+
+/**
+ * IOC statistics
+ */
+struct bfa_iocfc_stats_s {
+ struct bfa_fw_stats_s fw_stats; /* firmware IOC stats */
+};
+
+/**
+ * IOC attributes returned in queries
+ */
+struct bfa_iocfc_attr_s {
+ struct bfa_iocfc_cfg_s config; /* IOCFC config */
+ struct bfa_iocfc_intr_attr_s intr_attr; /* interrupt attr */
+};
+
+#define BFA_IOCFC_PATHTOV_MAX 60
+#define BFA_IOCFC_QDEPTH_MAX 2000
+
+#endif /* __BFA_DEFS_IOC_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h b/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h
new file mode 100644
index 000000000000..7cb63ea98f38
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_ipfc.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DEFS_IPFC_H__
+#define __BFA_DEFS_IPFC_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/types.h>
+#include <defs/bfa_defs_types.h>
+
+/**
+ * FCS ip remote port states
+ */
+enum bfa_iprp_state {
+ BFA_IPRP_UNINIT = 0, /* PORT is not yet initialized */
+ BFA_IPRP_ONLINE = 1, /* process login is complete */
+ BFA_IPRP_OFFLINE = 2, /* iprp is offline */
+};
+
+/**
+ * FCS remote port statistics
+ */
+struct bfa_iprp_stats_s {
+ u32 offlines;
+ u32 onlines;
+ u32 rscns;
+ u32 plogis;
+ u32 logos;
+ u32 plogi_timeouts;
+ u32 plogi_rejects;
+};
+
+/**
+ * FCS iprp attribute returned in queries
+ */
+struct bfa_iprp_attr_s {
+ enum bfa_iprp_state state;
+};
+
+struct bfa_ipfc_stats_s {
+ u32 arp_sent;
+ u32 arp_recv;
+ u32 arp_reply_sent;
+ u32 arp_reply_recv;
+ u32 farp_sent;
+ u32 farp_recv;
+ u32 farp_reply_sent;
+ u32 farp_reply_recv;
+ u32 farp_reject_sent;
+ u32 farp_reject_recv;
+};
+
+struct bfa_ipfc_attr_s {
+ bfa_boolean_t enabled;
+};
+
+#endif /* __BFA_DEFS_IPFC_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h
new file mode 100644
index 000000000000..2ec769903d24
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_itnim.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DEFS_ITNIM_H__
+#define __BFA_DEFS_ITNIM_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/types.h>
+
+/**
+ * FCS itnim states
+ */
+enum bfa_itnim_state {
+ BFA_ITNIM_OFFLINE = 0, /* offline */
+ BFA_ITNIM_PRLI_SEND = 1, /* prli send */
+ BFA_ITNIM_PRLI_SENT = 2, /* prli sent */
+ BFA_ITNIM_PRLI_RETRY = 3, /* prli retry */
+ BFA_ITNIM_HCB_ONLINE = 4, /* online callback */
+ BFA_ITNIM_ONLINE = 5, /* online */
+ BFA_ITNIM_HCB_OFFLINE = 6, /* offline callback */
+ BFA_ITNIM_INITIATIOR = 7, /* initiator */
+};
+
+struct bfa_itnim_hal_stats_s {
+ u32 onlines; /* ITN nexus onlines (PRLI done) */
+ u32 offlines; /* ITN Nexus offlines */
+ u32 creates; /* ITN create requests */
+ u32 deletes; /* ITN delete requests */
+ u32 create_comps; /* ITN create completions */
+ u32 delete_comps; /* ITN delete completions */
+ u32 sler_events; /* SLER (sequence level error
+ * recovery) events */
+ u32 ioc_disabled; /* Num IOC disables */
+ u32 cleanup_comps; /* ITN cleanup completions */
+ u32 tm_cmnds; /* task management(TM) cmnds sent */
+ u32 tm_fw_rsps; /* TM cmds firmware responses */
+ u32 tm_success; /* TM successes */
+ u32 tm_failures; /* TM failures */
+ u32 tm_io_comps; /* TM IO completions */
+ u32 tm_qresumes; /* TM queue resumes (after waiting
+ * for resources)
+ */
+ u32 tm_iocdowns; /* TM cmnds affected by IOC down */
+ u32 tm_cleanups; /* TM cleanups */
+ u32 tm_cleanup_comps;
+ /* TM cleanup completions */
+ u32 ios; /* IO requests */
+ u32 io_comps; /* IO completions */
+ u64 input_reqs; /* INPUT requests */
+ u64 output_reqs; /* OUTPUT requests */
+};
+
+/**
+ * FCS remote port statistics
+ */
+struct bfa_itnim_stats_s {
+ u32 onlines; /* num rport online */
+ u32 offlines; /* num rport offline */
+ u32 prli_sent; /* num prli sent out */
+ u32 fcxp_alloc_wait;/* num fcxp alloc waits */
+ u32 prli_rsp_err; /* num prli rsp errors */
+ u32 prli_rsp_acc; /* num prli rsp accepts */
+ u32 initiator; /* rport is an initiator */
+ u32 prli_rsp_parse_err; /* prli rsp parsing errors */
+ u32 prli_rsp_rjt; /* num prli rsp rejects */
+ u32 timeout; /* num timeouts detected */
+ u32 sler; /* num sler notification from BFA */
+ u32 rsvd;
+ struct bfa_itnim_hal_stats_s hal_stats;
+};
+
+/**
+ * FCS itnim attributes returned in queries
+ */
+struct bfa_itnim_attr_s {
+ enum bfa_itnim_state state; /* FCS itnim state */
+ u8 retry; /* data retransmision support */
+ u8 task_retry_id; /* task retry ident support */
+ u8 rec_support; /* REC supported */
+ u8 conf_comp; /* confirmed completion supp */
+};
+
+/**
+ * BFA ITNIM events.
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_ITNIM_AEN_NEW: [in]: None [out]: vf_id, lpwwn
+ * BFA_ITNIM_AEN_DELETE: [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets),
+ * [out]: vf_id, ppwwn, lpwwn, rpwwn
+ * BFA_ITNIM_AEN_ONLINE: [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets),
+ * [out]: vf_id, ppwwn, lpwwn, rpwwn
+ * BFA_ITNIM_AEN_OFFLINE: [in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets),
+ * [out]: vf_id, ppwwn, lpwwn, rpwwn
+ * BFA_ITNIM_AEN_DISCONNECT:[in]: vf_id, lpwwn, rpwwn (0 = all fcp4 targets),
+ * [out]: vf_id, ppwwn, lpwwn, rpwwn
+ */
+enum bfa_itnim_aen_event {
+ BFA_ITNIM_AEN_ONLINE = 1, /* Target online */
+ BFA_ITNIM_AEN_OFFLINE = 2, /* Target offline */
+ BFA_ITNIM_AEN_DISCONNECT = 3, /* Target disconnected */
+};
+
+/**
+ * BFA ITNIM event data structure.
+ */
+struct bfa_itnim_aen_data_s {
+ u16 vf_id; /* vf_id of the IT nexus */
+ u16 rsvd[3];
+ wwn_t ppwwn; /* WWN of its physical port */
+ wwn_t lpwwn; /* WWN of logical port */
+ wwn_t rpwwn; /* WWN of remote(target) port */
+};
+
+#endif /* __BFA_DEFS_ITNIM_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_led.h b/drivers/scsi/bfa/include/defs/bfa_defs_led.h
new file mode 100644
index 000000000000..62039273264e
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_led.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_LED_H__
+#define __BFA_DEFS_LED_H__
+
+#define BFA_LED_MAX_NUM 3
+
+enum bfa_led_op {
+ BFA_LED_OFF = 0,
+ BFA_LED_ON = 1,
+ BFA_LED_FLICK = 2,
+ BFA_LED_BLINK = 3,
+};
+
+enum bfa_led_color {
+ BFA_LED_GREEN = 0,
+ BFA_LED_AMBER = 1,
+};
+
+#endif /* __BFA_DEFS_LED_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_lport.h b/drivers/scsi/bfa/include/defs/bfa_defs_lport.h
new file mode 100644
index 000000000000..7359f82aacfc
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_lport.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_LPORT_H__
+#define __BFA_DEFS_LPORT_H__
+
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_port.h>
+
+/**
+ * BFA AEN logical port events.
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_LPORT_AEN_NEW: [in]: None [out]: vf_id, ppwwn, lpwwn, roles
+ * BFA_LPORT_AEN_DELETE: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_ONLINE: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_OFFLINE: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_DISCONNECT:[in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_NEW_PROP: [in]: None [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_DELETE_PROP: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_NEW_STANDARD: [in]: None [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_DELETE_STANDARD: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_NPIV_DUP_WWN: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_NPIV_FABRIC_MAX: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ * BFA_LPORT_AEN_NPIV_UNKNOWN: [in]: lpwwn [out]: vf_id, ppwwn. lpwwn, roles
+ */
+enum bfa_lport_aen_event {
+ BFA_LPORT_AEN_NEW = 1, /* LPort created event */
+ BFA_LPORT_AEN_DELETE = 2, /* LPort deleted event */
+ BFA_LPORT_AEN_ONLINE = 3, /* LPort online event */
+ BFA_LPORT_AEN_OFFLINE = 4, /* LPort offline event */
+ BFA_LPORT_AEN_DISCONNECT = 5, /* LPort disconnect event */
+ BFA_LPORT_AEN_NEW_PROP = 6, /* VPort created event */
+ BFA_LPORT_AEN_DELETE_PROP = 7, /* VPort deleted event */
+ BFA_LPORT_AEN_NEW_STANDARD = 8, /* VPort created event */
+ BFA_LPORT_AEN_DELETE_STANDARD = 9, /* VPort deleted event */
+ BFA_LPORT_AEN_NPIV_DUP_WWN = 10, /* VPort configured with
+ * duplicate WWN event
+ */
+ BFA_LPORT_AEN_NPIV_FABRIC_MAX = 11, /* Max NPIV in fabric/fport */
+ BFA_LPORT_AEN_NPIV_UNKNOWN = 12, /* Unknown NPIV Error code event */
+};
+
+/**
+ * BFA AEN event data structure
+ */
+struct bfa_lport_aen_data_s {
+ u16 vf_id; /* vf_id of this logical port */
+ u16 rsvd;
+ enum bfa_port_role roles; /* Logical port mode,IM/TM/IP etc */
+ wwn_t ppwwn; /* WWN of its physical port */
+ wwn_t lpwwn; /* WWN of this logical port */
+};
+
+#endif /* __BFA_DEFS_LPORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h
new file mode 100644
index 000000000000..13fd4ab6aae2
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_mfg.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DEFS_MFG_H__
+#define __BFA_DEFS_MFG_H__
+
+#include <bfa_os_inc.h>
+
+/**
+ * Manufacturing block version
+ */
+#define BFA_MFG_VERSION 1
+
+/**
+ * Manufacturing block format
+ */
+#define BFA_MFG_SERIALNUM_SIZE 11
+#define BFA_MFG_PARTNUM_SIZE 14
+#define BFA_MFG_SUPPLIER_ID_SIZE 10
+#define BFA_MFG_SUPPLIER_PARTNUM_SIZE 20
+#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE 20
+#define BFA_MFG_SUPPLIER_REVISION_SIZE 4
+#define STRSZ(_n) (((_n) + 4) & ~3)
+
+/**
+ * VPD data length
+ */
+#define BFA_MFG_VPD_LEN 256
+
+/**
+ * All numerical fields are in big-endian format.
+ */
+struct bfa_mfg_vpd_s {
+ u8 version; /* vpd data version */
+ u8 vpd_sig[3]; /* characters 'V', 'P', 'D' */
+ u8 chksum; /* u8 checksum */
+ u8 vendor; /* vendor */
+ u8 len; /* vpd data length excluding header */
+ u8 rsv;
+ u8 data[BFA_MFG_VPD_LEN]; /* vpd data */
+};
+
+#pragma pack(1)
+
+#endif /* __BFA_DEFS_MFG_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pci.h b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h
new file mode 100644
index 000000000000..c9b83321694b
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pci.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_PCI_H__
+#define __BFA_DEFS_PCI_H__
+
+/**
+ * PCI device and vendor ID information
+ */
+enum {
+ BFA_PCI_VENDOR_ID_BROCADE = 0x1657,
+ BFA_PCI_DEVICE_ID_FC_8G2P = 0x13,
+ BFA_PCI_DEVICE_ID_FC_8G1P = 0x17,
+ BFA_PCI_DEVICE_ID_CT = 0x14,
+};
+
+/**
+ * PCI sub-system device and vendor ID information
+ */
+enum {
+ BFA_PCI_FCOE_SSDEVICE_ID = 0x14,
+};
+
+#define BFA_PCI_ACCESS_RANGES 1 /* Maximum number of device address ranges
+ * mapped through different BAR(s). */
+
+#endif /* __BFA_DEFS_PCI_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pm.h b/drivers/scsi/bfa/include/defs/bfa_defs_pm.h
new file mode 100644
index 000000000000..e8d6d959006e
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pm.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_PM_H__
+#define __BFA_DEFS_PM_H__
+
+#include <bfa_os_inc.h>
+
+/**
+ * BFA power management device states
+ */
+enum bfa_pm_ds {
+ BFA_PM_DS_D0 = 0, /* full power mode */
+ BFA_PM_DS_D1 = 1, /* power save state 1 */
+ BFA_PM_DS_D2 = 2, /* power save state 2 */
+ BFA_PM_DS_D3 = 3, /* power off state */
+};
+
+#endif /* __BFA_DEFS_PM_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pom.h b/drivers/scsi/bfa/include/defs/bfa_defs_pom.h
new file mode 100644
index 000000000000..d9fa278472b7
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pom.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DEFS_POM_H__
+#define __BFA_DEFS_POM_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_types.h>
+
+/**
+ * POM health status levels for each attributes.
+ */
+enum bfa_pom_entry_health {
+ BFA_POM_HEALTH_NOINFO = 1, /* no information */
+ BFA_POM_HEALTH_NORMAL = 2, /* health is normal */
+ BFA_POM_HEALTH_WARNING = 3, /* warning level */
+ BFA_POM_HEALTH_ALARM = 4, /* alarming level */
+};
+
+/**
+ * Reading of temperature/voltage/current/power
+ */
+struct bfa_pom_entry_s {
+ enum bfa_pom_entry_health health; /* POM entry health */
+ u32 curr_value; /* current value */
+ u32 thr_warn_high; /* threshold warning high */
+ u32 thr_warn_low; /* threshold warning low */
+ u32 thr_alarm_low; /* threshold alaram low */
+ u32 thr_alarm_high; /* threshold alarm high */
+};
+
+/**
+ * POM attributes
+ */
+struct bfa_pom_attr_s {
+ struct bfa_pom_entry_s temperature; /* centigrade */
+ struct bfa_pom_entry_s voltage; /* volts */
+ struct bfa_pom_entry_s curr; /* milli amps */
+ struct bfa_pom_entry_s txpower; /* micro watts */
+ struct bfa_pom_entry_s rxpower; /* micro watts */
+};
+
+#endif /* __BFA_DEFS_POM_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_port.h b/drivers/scsi/bfa/include/defs/bfa_defs_port.h
new file mode 100644
index 000000000000..de0696c81bc4
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_port.h
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_PORT_H__
+#define __BFA_DEFS_PORT_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/types.h>
+#include <defs/bfa_defs_pport.h>
+#include <defs/bfa_defs_ioc.h>
+
+#define BFA_FCS_FABRIC_IPADDR_SZ 16
+
+/**
+ * symbolic names for base port/virtual port
+ */
+#define BFA_SYMNAME_MAXLEN 128 /* vmware/windows uses 128 bytes */
+struct bfa_port_symname_s {
+ char symname[BFA_SYMNAME_MAXLEN];
+};
+
+/**
+* Roles of FCS port:
+ * - FCP IM and FCP TM roles cannot be enabled together for a FCS port
+ * - Create multiple ports if both IM and TM functions required.
+ * - Atleast one role must be specified.
+ */
+enum bfa_port_role {
+ BFA_PORT_ROLE_FCP_IM = 0x01, /* FCP initiator role */
+ BFA_PORT_ROLE_FCP_TM = 0x02, /* FCP target role */
+ BFA_PORT_ROLE_FCP_IPFC = 0x04, /* IP over FC role */
+ BFA_PORT_ROLE_FCP_MAX = BFA_PORT_ROLE_FCP_IPFC | BFA_PORT_ROLE_FCP_IM
+};
+
+/**
+ * FCS port configuration.
+ */
+struct bfa_port_cfg_s {
+ wwn_t pwwn; /* port wwn */
+ wwn_t nwwn; /* node wwn */
+ struct bfa_port_symname_s sym_name; /* vm port symbolic name */
+ enum bfa_port_role roles; /* FCS port roles */
+ u32 rsvd;
+ u8 tag[16]; /* opaque tag from application */
+};
+
+/**
+ * FCS port states
+ */
+enum bfa_port_state {
+ BFA_PORT_UNINIT = 0, /* PORT is not yet initialized */
+ BFA_PORT_FDISC = 1, /* FDISC is in progress */
+ BFA_PORT_ONLINE = 2, /* login to fabric is complete */
+ BFA_PORT_OFFLINE = 3, /* No login to fabric */
+};
+
+/**
+ * FCS port type. Required for VmWare.
+ */
+enum bfa_port_type {
+ BFA_PORT_TYPE_PHYSICAL = 0,
+ BFA_PORT_TYPE_VIRTUAL,
+};
+
+/**
+ * FCS port offline reason. Required for VmWare.
+ */
+enum bfa_port_offline_reason {
+ BFA_PORT_OFFLINE_UNKNOWN = 0,
+ BFA_PORT_OFFLINE_LINKDOWN,
+ BFA_PORT_OFFLINE_FAB_UNSUPPORTED, /* NPIV not supported by the
+ * fabric */
+ BFA_PORT_OFFLINE_FAB_NORESOURCES,
+ BFA_PORT_OFFLINE_FAB_LOGOUT,
+};
+
+/**
+ * FCS lport info. Required for VmWare.
+ */
+struct bfa_port_info_s {
+ u8 port_type; /* bfa_port_type_t : physical or
+ * virtual */
+ u8 port_state; /* one of bfa_port_state values */
+ u8 offline_reason; /* one of bfa_port_offline_reason_t
+ * values */
+ wwn_t port_wwn;
+ wwn_t node_wwn;
+
+ /*
+ * following 4 feilds are valid for Physical Ports only
+ */
+ u32 max_vports_supp; /* Max supported vports */
+ u32 num_vports_inuse; /* Num of in use vports */
+ u32 max_rports_supp; /* Max supported rports */
+ u32 num_rports_inuse; /* Num of doscovered rports */
+
+};
+
+/**
+ * FCS port statistics
+ */
+struct bfa_port_stats_s {
+ u32 ns_plogi_sent;
+ u32 ns_plogi_rsp_err;
+ u32 ns_plogi_acc_err;
+ u32 ns_plogi_accepts;
+ u32 ns_rejects; /* NS command rejects */
+ u32 ns_plogi_unknown_rsp;
+ u32 ns_plogi_alloc_wait;
+
+ u32 ns_retries; /* NS command retries */
+ u32 ns_timeouts; /* NS command timeouts */
+
+ u32 ns_rspnid_sent;
+ u32 ns_rspnid_accepts;
+ u32 ns_rspnid_rsp_err;
+ u32 ns_rspnid_rejects;
+ u32 ns_rspnid_alloc_wait;
+
+ u32 ns_rftid_sent;
+ u32 ns_rftid_accepts;
+ u32 ns_rftid_rsp_err;
+ u32 ns_rftid_rejects;
+ u32 ns_rftid_alloc_wait;
+
+ u32 ns_rffid_sent;
+ u32 ns_rffid_accepts;
+ u32 ns_rffid_rsp_err;
+ u32 ns_rffid_rejects;
+ u32 ns_rffid_alloc_wait;
+
+ u32 ns_gidft_sent;
+ u32 ns_gidft_accepts;
+ u32 ns_gidft_rsp_err;
+ u32 ns_gidft_rejects;
+ u32 ns_gidft_unknown_rsp;
+ u32 ns_gidft_alloc_wait;
+
+ /*
+ * Mgmt Server stats
+ */
+ u32 ms_retries; /* MS command retries */
+ u32 ms_timeouts; /* MS command timeouts */
+ u32 ms_plogi_sent;
+ u32 ms_plogi_rsp_err;
+ u32 ms_plogi_acc_err;
+ u32 ms_plogi_accepts;
+ u32 ms_rejects; /* NS command rejects */
+ u32 ms_plogi_unknown_rsp;
+ u32 ms_plogi_alloc_wait;
+
+ u32 num_rscn; /* Num of RSCN received */
+ u32 num_portid_rscn;/* Num portid format RSCN
+ * received */
+
+ u32 uf_recvs; /* unsolicited recv frames */
+ u32 uf_recv_drops; /* dropped received frames */
+
+ u32 rsvd; /* padding for 64 bit alignment */
+};
+
+/**
+ * BFA port attribute returned in queries
+ */
+struct bfa_port_attr_s {
+ enum bfa_port_state state; /* port state */
+ u32 pid; /* port ID */
+ struct bfa_port_cfg_s port_cfg; /* port configuration */
+ enum bfa_pport_type port_type; /* current topology */
+ u32 loopback; /* cable is externally looped back */
+ wwn_t fabric_name; /* attached switch's nwwn */
+ u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; /* attached
+ * fabric's ip addr */
+};
+
+/**
+ * BFA physical port Level events
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_PORT_AEN_ONLINE: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_OFFLINE: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_RLIR: [in]: None [out]: pwwn, rlir_data, rlir_len
+ * BFA_PORT_AEN_SFP_INSERT: [in]: pwwn [out]: port_id, pwwn
+ * BFA_PORT_AEN_SFP_REMOVE: [in]: pwwn [out]: port_id, pwwn
+ * BFA_PORT_AEN_SFP_POM: [in]: pwwn [out]: level, port_id, pwwn
+ * BFA_PORT_AEN_ENABLE: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_DISABLE: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_AUTH_ON: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_AUTH_OFF: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_DISCONNECT: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_QOS_NEG: [in]: pwwn [out]: pwwn
+ * BFA_PORT_AEN_FABRIC_NAME_CHANGE: [in]: pwwn, [out]: pwwn, fwwn
+ *
+ */
+enum bfa_port_aen_event {
+ BFA_PORT_AEN_ONLINE = 1, /* Physical Port online event */
+ BFA_PORT_AEN_OFFLINE = 2, /* Physical Port offline event */
+ BFA_PORT_AEN_RLIR = 3, /* RLIR event, not supported */
+ BFA_PORT_AEN_SFP_INSERT = 4, /* SFP inserted event */
+ BFA_PORT_AEN_SFP_REMOVE = 5, /* SFP removed event */
+ BFA_PORT_AEN_SFP_POM = 6, /* SFP POM event */
+ BFA_PORT_AEN_ENABLE = 7, /* Physical Port enable event */
+ BFA_PORT_AEN_DISABLE = 8, /* Physical Port disable event */
+ BFA_PORT_AEN_AUTH_ON = 9, /* Physical Port auth success event */
+ BFA_PORT_AEN_AUTH_OFF = 10, /* Physical Port auth fail event */
+ BFA_PORT_AEN_DISCONNECT = 11, /* Physical Port disconnect event */
+ BFA_PORT_AEN_QOS_NEG = 12, /* Base Port QOS negotiation event */
+ BFA_PORT_AEN_FABRIC_NAME_CHANGE = 13, /* Fabric Name/WWN change
+ * event */
+ BFA_PORT_AEN_SFP_ACCESS_ERROR = 14, /* SFP read error event */
+ BFA_PORT_AEN_SFP_UNSUPPORT = 15, /* Unsupported SFP event */
+};
+
+enum bfa_port_aen_sfp_pom {
+ BFA_PORT_AEN_SFP_POM_GREEN = 1, /* Normal */
+ BFA_PORT_AEN_SFP_POM_AMBER = 2, /* Warning */
+ BFA_PORT_AEN_SFP_POM_RED = 3, /* Critical */
+ BFA_PORT_AEN_SFP_POM_MAX = BFA_PORT_AEN_SFP_POM_RED
+};
+
+struct bfa_port_aen_data_s {
+ enum bfa_ioc_type_e ioc_type;
+ wwn_t pwwn; /* WWN of the physical port */
+ wwn_t fwwn; /* WWN of the fabric port */
+ mac_t mac; /* MAC addres of the ethernet port,
+ * applicable to CNA port only */
+ int phy_port_num; /*! For SFP related events */
+ enum bfa_port_aen_sfp_pom level; /* Only transitions will
+ * be informed */
+};
+
+#endif /* __BFA_DEFS_PORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_pport.h b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
new file mode 100644
index 000000000000..a000bc4e2d4a
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_pport.h
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_PPORT_H__
+#define __BFA_DEFS_PPORT_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/fc.h>
+#include <defs/bfa_defs_types.h>
+#include <defs/bfa_defs_qos.h>
+#include <cna/pstats/phyport_defs.h>
+
+/* Modify char* port_stt[] in bfal_port.c if a new state was added */
+enum bfa_pport_states {
+ BFA_PPORT_ST_UNINIT = 1,
+ BFA_PPORT_ST_ENABLING_QWAIT = 2,
+ BFA_PPORT_ST_ENABLING = 3,
+ BFA_PPORT_ST_LINKDOWN = 4,
+ BFA_PPORT_ST_LINKUP = 5,
+ BFA_PPORT_ST_DISABLING_QWAIT = 6,
+ BFA_PPORT_ST_DISABLING = 7,
+ BFA_PPORT_ST_DISABLED = 8,
+ BFA_PPORT_ST_STOPPED = 9,
+ BFA_PPORT_ST_IOCDOWN = 10,
+ BFA_PPORT_ST_IOCDIS = 11,
+ BFA_PPORT_ST_FWMISMATCH = 12,
+ BFA_PPORT_ST_MAX_STATE,
+};
+
+/**
+ * Port speed settings. Each specific speed is a bit field. Use multiple
+ * bits to specify speeds to be selected for auto-negotiation.
+ */
+enum bfa_pport_speed {
+ BFA_PPORT_SPEED_UNKNOWN = 0,
+ BFA_PPORT_SPEED_1GBPS = 1,
+ BFA_PPORT_SPEED_2GBPS = 2,
+ BFA_PPORT_SPEED_4GBPS = 4,
+ BFA_PPORT_SPEED_8GBPS = 8,
+ BFA_PPORT_SPEED_10GBPS = 10,
+ BFA_PPORT_SPEED_AUTO =
+ (BFA_PPORT_SPEED_1GBPS | BFA_PPORT_SPEED_2GBPS |
+ BFA_PPORT_SPEED_4GBPS | BFA_PPORT_SPEED_8GBPS),
+};
+
+/**
+ * Port operational type (in sync with SNIA port type).
+ */
+enum bfa_pport_type {
+ BFA_PPORT_TYPE_UNKNOWN = 1, /* port type is unkown */
+ BFA_PPORT_TYPE_TRUNKED = 2, /* Trunked mode */
+ BFA_PPORT_TYPE_NPORT = 5, /* P2P with switched fabric */
+ BFA_PPORT_TYPE_NLPORT = 6, /* public loop */
+ BFA_PPORT_TYPE_LPORT = 20, /* private loop */
+ BFA_PPORT_TYPE_P2P = 21, /* P2P with no switched fabric */
+ BFA_PPORT_TYPE_VPORT = 22, /* NPIV - virtual port */
+};
+
+/**
+ * Port topology setting. A port's topology and fabric login status
+ * determine its operational type.
+ */
+enum bfa_pport_topology {
+ BFA_PPORT_TOPOLOGY_NONE = 0, /* No valid topology */
+ BFA_PPORT_TOPOLOGY_P2P = 1, /* P2P only */
+ BFA_PPORT_TOPOLOGY_LOOP = 2, /* LOOP topology */
+ BFA_PPORT_TOPOLOGY_AUTO = 3, /* auto topology selection */
+};
+
+/**
+ * Physical port loopback types.
+ */
+enum bfa_pport_opmode {
+ BFA_PPORT_OPMODE_NORMAL = 0x00, /* normal non-loopback mode */
+ BFA_PPORT_OPMODE_LB_INT = 0x01, /* internal loop back */
+ BFA_PPORT_OPMODE_LB_SLW = 0x02, /* serial link wrapback (serdes) */
+ BFA_PPORT_OPMODE_LB_EXT = 0x04, /* external loop back (serdes) */
+ BFA_PPORT_OPMODE_LB_CBL = 0x08, /* cabled loop back */
+ BFA_PPORT_OPMODE_LB_NLINT = 0x20, /* NL_Port internal loopback */
+};
+
+#define BFA_PPORT_OPMODE_LB_HARD(_mode) \
+ ((_mode == BFA_PPORT_OPMODE_LB_INT) || \
+ (_mode == BFA_PPORT_OPMODE_LB_SLW) || \
+ (_mode == BFA_PPORT_OPMODE_LB_EXT))
+
+/**
+ Port State (in sync with SNIA port state).
+ */
+enum bfa_pport_snia_state {
+ BFA_PPORT_STATE_UNKNOWN = 1, /* port is not initialized */
+ BFA_PPORT_STATE_ONLINE = 2, /* port is ONLINE */
+ BFA_PPORT_STATE_DISABLED = 3, /* port is disabled by user */
+ BFA_PPORT_STATE_BYPASSED = 4, /* port is bypassed (in LOOP) */
+ BFA_PPORT_STATE_DIAG = 5, /* port diagnostics is active */
+ BFA_PPORT_STATE_LINKDOWN = 6, /* link is down */
+ BFA_PPORT_STATE_LOOPBACK = 8, /* port is looped back */
+};
+
+/**
+ * Port link state
+ */
+enum bfa_pport_linkstate {
+ BFA_PPORT_LINKUP = 1, /* Physical port/Trunk link up */
+ BFA_PPORT_LINKDOWN = 2, /* Physical port/Trunk link down */
+ BFA_PPORT_TRUNK_LINKDOWN = 3, /* Trunk link down (new tmaster) */
+};
+
+/**
+ * Port link state event
+ */
+#define bfa_pport_event_t enum bfa_pport_linkstate
+
+/**
+ * Port link state reason code
+ */
+enum bfa_pport_linkstate_rsn {
+ BFA_PPORT_LINKSTATE_RSN_NONE = 0,
+ BFA_PPORT_LINKSTATE_RSN_DISABLED = 1,
+ BFA_PPORT_LINKSTATE_RSN_RX_NOS = 2,
+ BFA_PPORT_LINKSTATE_RSN_RX_OLS = 3,
+ BFA_PPORT_LINKSTATE_RSN_RX_LIP = 4,
+ BFA_PPORT_LINKSTATE_RSN_RX_LIPF7 = 5,
+ BFA_PPORT_LINKSTATE_RSN_SFP_REMOVED = 6,
+ BFA_PPORT_LINKSTATE_RSN_PORT_FAULT = 7,
+ BFA_PPORT_LINKSTATE_RSN_RX_LOS = 8,
+ BFA_PPORT_LINKSTATE_RSN_LOCAL_FAULT = 9,
+ BFA_PPORT_LINKSTATE_RSN_REMOTE_FAULT = 10,
+ BFA_PPORT_LINKSTATE_RSN_TIMEOUT = 11,
+
+
+
+ /* CEE related reason codes/errors */
+ CEE_LLDP_INFO_AGED_OUT = 20,
+ CEE_LLDP_SHUTDOWN_TLV_RCVD = 21,
+ CEE_PEER_NOT_ADVERTISE_DCBX = 22,
+ CEE_PEER_NOT_ADVERTISE_PG = 23,
+ CEE_PEER_NOT_ADVERTISE_PFC = 24,
+ CEE_PEER_NOT_ADVERTISE_FCOE = 25,
+ CEE_PG_NOT_COMPATIBLE = 26,
+ CEE_PFC_NOT_COMPATIBLE = 27,
+ CEE_FCOE_NOT_COMPATIBLE = 28,
+ CEE_BAD_PG_RCVD = 29,
+ CEE_BAD_BW_RCVD = 30,
+ CEE_BAD_PFC_RCVD = 31,
+ CEE_BAD_FCOE_PRI_RCVD = 32,
+ CEE_FCOE_PRI_PFC_OFF = 33,
+ CEE_DUP_CONTROL_TLV_RCVD = 34,
+ CEE_DUP_FEAT_TLV_RCVD = 35,
+ CEE_APPLY_NEW_CFG = 36, /* reason, not an error */
+ CEE_PROTOCOL_INIT = 37, /* reason, not an error */
+ CEE_PHY_LINK_DOWN = 38,
+ CEE_LLS_FCOE_ABSENT = 39,
+ CEE_LLS_FCOE_DOWN = 40
+};
+
+/**
+ * Default Target Rate Limiting Speed.
+ */
+#define BFA_PPORT_DEF_TRL_SPEED BFA_PPORT_SPEED_1GBPS
+
+/**
+ * Physical port configuration
+ */
+struct bfa_pport_cfg_s {
+ u8 topology; /* bfa_pport_topology */
+ u8 speed; /* enum bfa_pport_speed */
+ u8 trunked; /* trunked or not */
+ u8 qos_enabled; /* qos enabled or not */
+ u8 trunk_ports; /* bitmap of trunked ports */
+ u8 cfg_hardalpa; /* is hard alpa configured */
+ u16 maxfrsize; /* maximum frame size */
+ u8 hardalpa; /* configured hard alpa */
+ u8 rx_bbcredit; /* receive buffer credits */
+ u8 tx_bbcredit; /* transmit buffer credits */
+ u8 ratelimit; /* ratelimit enabled or not */
+ u8 trl_def_speed; /* ratelimit default speed */
+ u8 rsvd[3];
+ u16 path_tov; /* device path timeout */
+ u16 q_depth; /* SCSI Queue depth */
+};
+
+/**
+ * Port attribute values.
+ */
+struct bfa_pport_attr_s {
+ /*
+ * Static fields
+ */
+ wwn_t nwwn; /* node wwn */
+ wwn_t pwwn; /* port wwn */
+ enum fc_cos cos_supported; /* supported class of services */
+ u32 rsvd;
+ struct fc_symname_s port_symname; /* port symbolic name */
+ enum bfa_pport_speed speed_supported; /* supported speeds */
+ bfa_boolean_t pbind_enabled; /* Will be set if Persistent binding
+ * enabled. Relevant only in Windows
+ */
+
+ /*
+ * Configured values
+ */
+ struct bfa_pport_cfg_s pport_cfg; /* pport cfg */
+
+ /*
+ * Dynamic field - info from BFA
+ */
+ enum bfa_pport_states port_state; /* current port state */
+ enum bfa_pport_speed speed; /* current speed */
+ enum bfa_pport_topology topology; /* current topology */
+ bfa_boolean_t beacon; /* current beacon status */
+ bfa_boolean_t link_e2e_beacon;/* set if link beacon on */
+ bfa_boolean_t plog_enabled; /* set if portlog is enabled*/
+
+ /*
+ * Dynamic field - info from FCS
+ */
+ u32 pid; /* port ID */
+ enum bfa_pport_type port_type; /* current topology */
+ u32 loopback; /* external loopback */
+ u32 rsvd1;
+ u32 rsvd2; /* padding for 64 bit */
+};
+
+/**
+ * FC Port statistics.
+ */
+struct bfa_pport_fc_stats_s {
+ u64 secs_reset; /* seconds since stats is reset */
+ u64 tx_frames; /* transmitted frames */
+ u64 tx_words; /* transmitted words */
+ u64 rx_frames; /* received frames */
+ u64 rx_words; /* received words */
+ u64 lip_count; /* LIPs seen */
+ u64 nos_count; /* NOS count */
+ u64 error_frames; /* errored frames (sent?) */
+ u64 dropped_frames; /* dropped frames */
+ u64 link_failures; /* link failure count */
+ u64 loss_of_syncs; /* loss of sync count */
+ u64 loss_of_signals;/* loss of signal count */
+ u64 primseq_errs; /* primitive sequence protocol */
+ u64 bad_os_count; /* invalid ordered set */
+ u64 err_enc_out; /* Encoding error outside frame */
+ u64 invalid_crcs; /* frames received with invalid CRC*/
+ u64 undersized_frm; /* undersized frames */
+ u64 oversized_frm; /* oversized frames */
+ u64 bad_eof_frm; /* frames with bad EOF */
+ struct bfa_qos_stats_s qos_stats; /* QoS statistics */
+};
+
+/**
+ * Eth Port statistics.
+ */
+struct bfa_pport_eth_stats_s {
+ u64 secs_reset; /* seconds since stats is reset */
+ u64 frame_64; /* both rx and tx counter */
+ u64 frame_65_127; /* both rx and tx counter */
+ u64 frame_128_255; /* both rx and tx counter */
+ u64 frame_256_511; /* both rx and tx counter */
+ u64 frame_512_1023; /* both rx and tx counter */
+ u64 frame_1024_1518; /* both rx and tx counter */
+ u64 frame_1519_1522; /* both rx and tx counter */
+
+ u64 tx_bytes;
+ u64 tx_packets;
+ u64 tx_mcast_packets;
+ u64 tx_bcast_packets;
+ u64 tx_control_frame;
+ u64 tx_drop;
+ u64 tx_jabber;
+ u64 tx_fcs_error;
+ u64 tx_fragments;
+
+ u64 rx_bytes;
+ u64 rx_packets;
+ u64 rx_mcast_packets;
+ u64 rx_bcast_packets;
+ u64 rx_control_frames;
+ u64 rx_unknown_opcode;
+ u64 rx_drop;
+ u64 rx_jabber;
+ u64 rx_fcs_error;
+ u64 rx_alignment_error;
+ u64 rx_frame_length_error;
+ u64 rx_code_error;
+ u64 rx_fragments;
+
+ u64 rx_pause; /* BPC */
+ u64 rx_zero_pause; /* BPC Pause cancellation */
+ u64 tx_pause; /* BPC */
+ u64 tx_zero_pause; /* BPC Pause cancellation */
+ u64 rx_fcoe_pause; /* BPC */
+ u64 rx_fcoe_zero_pause; /* BPC Pause cancellation */
+ u64 tx_fcoe_pause; /* BPC */
+ u64 tx_fcoe_zero_pause; /* BPC Pause cancellation */
+};
+
+/**
+ * Port statistics.
+ */
+union bfa_pport_stats_u {
+ struct bfa_pport_fc_stats_s fc;
+ struct bfa_pport_eth_stats_s eth;
+};
+
+/**
+ * Port FCP mappings.
+ */
+struct bfa_pport_fcpmap_s {
+ char osdevname[256];
+ u32 bus;
+ u32 target;
+ u32 oslun;
+ u32 fcid;
+ wwn_t nwwn;
+ wwn_t pwwn;
+ u64 fcplun;
+ char luid[256];
+};
+
+/**
+ * Port RNID info.
+ */
+struct bfa_pport_rnid_s {
+ wwn_t wwn;
+ u32 unittype;
+ u32 portid;
+ u32 attached_nodes_num;
+ u16 ip_version;
+ u16 udp_port;
+ u8 ipaddr[16];
+ u16 rsvd;
+ u16 topologydiscoveryflags;
+};
+
+/**
+ * Link state information
+ */
+struct bfa_pport_link_s {
+ u8 linkstate; /* Link state bfa_pport_linkstate */
+ u8 linkstate_rsn; /* bfa_pport_linkstate_rsn_t */
+ u8 topology; /* P2P/LOOP bfa_pport_topology */
+ u8 speed; /* Link speed (1/2/4/8 G) */
+ u32 linkstate_opt; /* Linkstate optional data (debug) */
+ u8 trunked; /* Trunked or not (1 or 0) */
+ u8 resvd[3];
+ struct bfa_qos_attr_s qos_attr; /* QoS Attributes */
+ struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */
+ union {
+ struct {
+ u8 tmaster;/* Trunk Master or
+ * not (1 or 0) */
+ u8 tlinks; /* Trunk links bitmap
+ * (linkup) */
+ u8 resv1; /* Reserved */
+ } trunk_info;
+
+ struct {
+ u8 myalpa; /* alpa claimed */
+ u8 login_req; /* Login required or
+ * not (1 or 0) */
+ u8 alpabm_val;/* alpa bitmap valid
+ * or not (1 or 0) */
+ struct fc_alpabm_s alpabm; /* alpa bitmap */
+ } loop_info;
+ } tl;
+};
+
+#endif /* __BFA_DEFS_PPORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_qos.h b/drivers/scsi/bfa/include/defs/bfa_defs_qos.h
new file mode 100644
index 000000000000..aadbacd1d2d7
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_qos.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_QOS_H__
+#define __BFA_DEFS_QOS_H__
+
+/**
+ * QoS states
+ */
+enum bfa_qos_state {
+ BFA_QOS_ONLINE = 1, /* QoS is online */
+ BFA_QOS_OFFLINE = 2, /* QoS is offline */
+};
+
+
+/**
+ * QoS Priority levels.
+ */
+enum bfa_qos_priority {
+ BFA_QOS_UNKNOWN = 0,
+ BFA_QOS_HIGH = 1, /* QoS Priority Level High */
+ BFA_QOS_MED = 2, /* QoS Priority Level Medium */
+ BFA_QOS_LOW = 3, /* QoS Priority Level Low */
+};
+
+
+/**
+ * QoS bandwidth allocation for each priority level
+ */
+enum bfa_qos_bw_alloc {
+ BFA_QOS_BW_HIGH = 60, /* bandwidth allocation for High */
+ BFA_QOS_BW_MED = 30, /* bandwidth allocation for Medium */
+ BFA_QOS_BW_LOW = 10, /* bandwidth allocation for Low */
+};
+
+/**
+ * QoS attribute returned in QoS Query
+ */
+struct bfa_qos_attr_s {
+ enum bfa_qos_state state; /* QoS current state */
+ u32 total_bb_cr; /* Total BB Credits */
+};
+
+/**
+ * These fields should be displayed only from the CLI.
+ * There will be a separate BFAL API (get_qos_vc_attr ?)
+ * to retrieve this.
+ *
+ */
+#define BFA_QOS_MAX_VC 16
+
+struct bfa_qos_vc_info_s {
+ u8 vc_credit;
+ u8 borrow_credit;
+ u8 priority;
+ u8 resvd;
+};
+
+struct bfa_qos_vc_attr_s {
+ u16 total_vc_count; /* Total VC Count */
+ u16 shared_credit;
+ u32 elp_opmode_flags;
+ struct bfa_qos_vc_info_s vc_info[BFA_QOS_MAX_VC]; /* as many as
+ * total_vc_count */
+};
+
+/**
+ * QoS statistics
+ */
+struct bfa_qos_stats_s {
+ u32 flogi_sent; /* QoS Flogi sent */
+ u32 flogi_acc_recvd; /* QoS Flogi Acc received */
+ u32 flogi_rjt_recvd; /* QoS Flogi rejects received */
+ u32 flogi_retries; /* QoS Flogi retries */
+
+ u32 elp_recvd; /* QoS ELP received */
+ u32 elp_accepted; /* QoS ELP Accepted */
+ u32 elp_rejected; /* QoS ELP rejected */
+ u32 elp_dropped; /* QoS ELP dropped */
+
+ u32 qos_rscn_recvd; /* QoS RSCN received */
+ u32 rsvd; /* padding for 64 bit alignment */
+};
+
+#endif /* __BFA_DEFS_QOS_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_rport.h b/drivers/scsi/bfa/include/defs/bfa_defs_rport.h
new file mode 100644
index 000000000000..e0af59d6d2f6
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_rport.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_RPORT_H__
+#define __BFA_DEFS_RPORT_H__
+
+#include <bfa_os_inc.h>
+#include <protocol/types.h>
+#include <defs/bfa_defs_pport.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_qos.h>
+
+/**
+ * FCS remote port states
+ */
+enum bfa_rport_state {
+ BFA_RPORT_UNINIT = 0, /* PORT is not yet initialized */
+ BFA_RPORT_OFFLINE = 1, /* rport is offline */
+ BFA_RPORT_PLOGI = 2, /* PLOGI to rport is in progress */
+ BFA_RPORT_ONLINE = 3, /* login to rport is complete */
+ BFA_RPORT_PLOGI_RETRY = 4, /* retrying login to rport */
+ BFA_RPORT_NSQUERY = 5, /* nameserver query */
+ BFA_RPORT_ADISC = 6, /* ADISC authentication */
+ BFA_RPORT_LOGO = 7, /* logging out with rport */
+ BFA_RPORT_LOGORCV = 8, /* handling LOGO from rport */
+ BFA_RPORT_NSDISC = 9, /* re-discover rport */
+};
+
+/**
+ * Rport Scsi Function : Initiator/Target.
+ */
+enum bfa_rport_function {
+ BFA_RPORT_INITIATOR = 0x01, /* SCSI Initiator */
+ BFA_RPORT_TARGET = 0x02, /* SCSI Target */
+};
+
+/**
+ * port/node symbolic names for rport
+ */
+#define BFA_RPORT_SYMNAME_MAXLEN 255
+struct bfa_rport_symname_s {
+ char symname[BFA_RPORT_SYMNAME_MAXLEN];
+};
+
+struct bfa_rport_hal_stats_s {
+ u32 sm_un_cr; /* uninit: create events */
+ u32 sm_un_unexp; /* uninit: exception events */
+ u32 sm_cr_on; /* created: online events */
+ u32 sm_cr_del; /* created: delete events */
+ u32 sm_cr_hwf; /* created: IOC down */
+ u32 sm_cr_unexp; /* created: exception events */
+ u32 sm_fwc_rsp; /* fw create: f/w responses */
+ u32 sm_fwc_del; /* fw create: delete events */
+ u32 sm_fwc_off; /* fw create: offline events */
+ u32 sm_fwc_hwf; /* fw create: IOC down */
+ u32 sm_fwc_unexp; /* fw create: exception events*/
+ u32 sm_on_off; /* online: offline events */
+ u32 sm_on_del; /* online: delete events */
+ u32 sm_on_hwf; /* online: IOC down events */
+ u32 sm_on_unexp; /* online: exception events */
+ u32 sm_fwd_rsp; /* fw delete: fw responses */
+ u32 sm_fwd_del; /* fw delete: delete events */
+ u32 sm_fwd_hwf; /* fw delete: IOC down events */
+ u32 sm_fwd_unexp; /* fw delete: exception events*/
+ u32 sm_off_del; /* offline: delete events */
+ u32 sm_off_on; /* offline: online events */
+ u32 sm_off_hwf; /* offline: IOC down events */
+ u32 sm_off_unexp; /* offline: exception events */
+ u32 sm_del_fwrsp; /* delete: fw responses */
+ u32 sm_del_hwf; /* delete: IOC down events */
+ u32 sm_del_unexp; /* delete: exception events */
+ u32 sm_delp_fwrsp; /* delete pend: fw responses */
+ u32 sm_delp_hwf; /* delete pend: IOC downs */
+ u32 sm_delp_unexp; /* delete pend: exceptions */
+ u32 sm_offp_fwrsp; /* off-pending: fw responses */
+ u32 sm_offp_del; /* off-pending: deletes */
+ u32 sm_offp_hwf; /* off-pending: IOC downs */
+ u32 sm_offp_unexp; /* off-pending: exceptions */
+ u32 sm_iocd_off; /* IOC down: offline events */
+ u32 sm_iocd_del; /* IOC down: delete events */
+ u32 sm_iocd_on; /* IOC down: online events */
+ u32 sm_iocd_unexp; /* IOC down: exceptions */
+ u32 rsvd;
+};
+
+/**
+ * FCS remote port statistics
+ */
+struct bfa_rport_stats_s {
+ u32 offlines; /* remote port offline count */
+ u32 onlines; /* remote port online count */
+ u32 rscns; /* RSCN affecting rport */
+ u32 plogis; /* plogis sent */
+ u32 plogi_accs; /* plogi accepts */
+ u32 plogi_timeouts; /* plogi timeouts */
+ u32 plogi_rejects; /* rcvd plogi rejects */
+ u32 plogi_failed; /* local failure */
+ u32 plogi_rcvd; /* plogis rcvd */
+ u32 prli_rcvd; /* inbound PRLIs */
+ u32 adisc_rcvd; /* ADISCs received */
+ u32 adisc_rejects; /* recvd ADISC rejects */
+ u32 adisc_sent; /* ADISC requests sent */
+ u32 adisc_accs; /* ADISC accepted by rport */
+ u32 adisc_failed; /* ADISC failed (no response) */
+ u32 adisc_rejected; /* ADISC rejected by us */
+ u32 logos; /* logos sent */
+ u32 logo_accs; /* LOGO accepts from rport */
+ u32 logo_failed; /* LOGO failures */
+ u32 logo_rejected; /* LOGO rejects from rport */
+ u32 logo_rcvd; /* LOGO from remote port */
+
+ u32 rpsc_rcvd; /* RPSC received */
+ u32 rpsc_rejects; /* recvd RPSC rejects */
+ u32 rpsc_sent; /* RPSC requests sent */
+ u32 rpsc_accs; /* RPSC accepted by rport */
+ u32 rpsc_failed; /* RPSC failed (no response) */
+ u32 rpsc_rejected; /* RPSC rejected by us */
+
+ u32 rsvd;
+ struct bfa_rport_hal_stats_s hal_stats; /* BFA rport stats */
+};
+
+/**
+ * Rport's QoS attributes
+ */
+struct bfa_rport_qos_attr_s {
+ enum bfa_qos_priority qos_priority; /* rport's QoS priority */
+ u32 qos_flow_id; /* QoS flow Id */
+};
+
+/**
+ * FCS remote port attributes returned in queries
+ */
+struct bfa_rport_attr_s {
+ wwn_t nwwn; /* node wwn */
+ wwn_t pwwn; /* port wwn */
+ enum fc_cos cos_supported; /* supported class of services */
+ u32 pid; /* port ID */
+ u32 df_sz; /* Max payload size */
+ enum bfa_rport_state state; /* Rport State machine state */
+ enum fc_cos fc_cos; /* FC classes of services */
+ bfa_boolean_t cisc; /* CISC capable device */
+ struct bfa_rport_symname_s symname; /* Symbolic Name */
+ enum bfa_rport_function scsi_function; /* Initiator/Target */
+ struct bfa_rport_qos_attr_s qos_attr; /* qos attributes */
+ enum bfa_pport_speed curr_speed; /* operating speed got from
+ * RPSC ELS. UNKNOWN, if RPSC
+ * is not supported */
+ bfa_boolean_t trl_enforced; /* TRL enforced ? TRUE/FALSE */
+ enum bfa_pport_speed assigned_speed; /* Speed assigned by the user.
+ * will be used if RPSC is not
+ * supported by the rport */
+};
+
+#define bfa_rport_aen_qos_data_t struct bfa_rport_qos_attr_s
+
+/**
+ * BFA remote port events
+ * Arguments below are in BFAL context from Mgmt
+ * BFA_RPORT_AEN_ONLINE: [in]: lpwwn [out]: vf_id, lpwwn, rpwwn
+ * BFA_RPORT_AEN_OFFLINE: [in]: lpwwn [out]: vf_id, lpwwn, rpwwn
+ * BFA_RPORT_AEN_DISCONNECT:[in]: lpwwn [out]: vf_id, lpwwn, rpwwn
+ * BFA_RPORT_AEN_QOS_PRIO: [in]: lpwwn [out]: vf_id, lpwwn, rpwwn, prio
+ * BFA_RPORT_AEN_QOS_FLOWID:[in]: lpwwn [out]: vf_id, lpwwn, rpwwn, flow_id
+ */
+enum bfa_rport_aen_event {
+ BFA_RPORT_AEN_ONLINE = 1, /* RPort online event */
+ BFA_RPORT_AEN_OFFLINE = 2, /* RPort offline event */
+ BFA_RPORT_AEN_DISCONNECT = 3, /* RPort disconnect event */
+ BFA_RPORT_AEN_QOS_PRIO = 4, /* QOS priority change event */
+ BFA_RPORT_AEN_QOS_FLOWID = 5, /* QOS flow Id change event */
+};
+
+struct bfa_rport_aen_data_s {
+ u16 vf_id; /* vf_id of this logical port */
+ u16 rsvd[3];
+ wwn_t ppwwn; /* WWN of its physical port */
+ wwn_t lpwwn; /* WWN of this logical port */
+ wwn_t rpwwn; /* WWN of this remote port */
+ union {
+ bfa_rport_aen_qos_data_t qos;
+ } priv;
+};
+
+#endif /* __BFA_DEFS_RPORT_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_status.h b/drivers/scsi/bfa/include/defs/bfa_defs_status.h
new file mode 100644
index 000000000000..cdceaeb9f4b8
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_status.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DEFS_STATUS_H__
+#define __BFA_DEFS_STATUS_H__
+
+/**
+ * API status return values
+ *
+ * NOTE: The error msgs are auto generated from the comments. Only singe line
+ * comments are supported
+ */
+enum bfa_status {
+ BFA_STATUS_OK = 0, /* Success */
+ BFA_STATUS_FAILED = 1, /* Operation failed */
+ BFA_STATUS_EINVAL = 2, /* Invalid params Check input
+ * parameters */
+ BFA_STATUS_ENOMEM = 3, /* Out of resources */
+ BFA_STATUS_ENOSYS = 4, /* Function not implemented */
+ BFA_STATUS_ETIMER = 5, /* Timer expired - Retry, if
+ * persists, contact support */
+ BFA_STATUS_EPROTOCOL = 6, /* Protocol error */
+ BFA_STATUS_ENOFCPORTS = 7, /* No FC ports resources */
+ BFA_STATUS_NOFLASH = 8, /* Flash not present */
+ BFA_STATUS_BADFLASH = 9, /* Flash is corrupted or bad */
+ BFA_STATUS_SFP_UNSUPP = 10, /* Unsupported SFP - Replace SFP */
+ BFA_STATUS_UNKNOWN_VFID = 11, /* VF_ID not found */
+ BFA_STATUS_DATACORRUPTED = 12, /* Diag returned data corrupted
+ * contact support */
+ BFA_STATUS_DEVBUSY = 13, /* Device busy - Retry operation */
+ BFA_STATUS_ABORTED = 14, /* Operation aborted */
+ BFA_STATUS_NODEV = 15, /* Dev is not present */
+ BFA_STATUS_HDMA_FAILED = 16, /* Host dma failed contact support */
+ BFA_STATUS_FLASH_BAD_LEN = 17, /* Flash bad length */
+ BFA_STATUS_UNKNOWN_LWWN = 18, /* LPORT PWWN not found */
+ BFA_STATUS_UNKNOWN_RWWN = 19, /* RPORT PWWN not found */
+ BFA_STATUS_FCPT_LS_RJT = 20, /* Got LS_RJT for FC Pass
+ * through Req */
+ BFA_STATUS_VPORT_EXISTS = 21, /* VPORT already exists */
+ BFA_STATUS_VPORT_MAX = 22, /* Reached max VPORT supported
+ * limit */
+ BFA_STATUS_UNSUPP_SPEED = 23, /* Invalid Speed Check speed
+ * setting */
+ BFA_STATUS_INVLD_DFSZ = 24, /* Invalid Max data field size */
+ BFA_STATUS_CNFG_FAILED = 25, /* Setting can not be persisted */
+ BFA_STATUS_CMD_NOTSUPP = 26, /* Command/API not supported */
+ BFA_STATUS_NO_ADAPTER = 27, /* No Brocade Adapter Found */
+ BFA_STATUS_LINKDOWN = 28, /* Link is down - Check or replace
+ * SFP/cable */
+ BFA_STATUS_FABRIC_RJT = 29, /* Reject from attached fabric */
+ BFA_STATUS_UNKNOWN_VWWN = 30, /* VPORT PWWN not found */
+ BFA_STATUS_NSLOGIN_FAILED = 31, /* Nameserver login failed */
+ BFA_STATUS_NO_RPORTS = 32, /* No remote ports found */
+ BFA_STATUS_NSQUERY_FAILED = 33, /* Nameserver query failed */
+ BFA_STATUS_PORT_OFFLINE = 34, /* Port is not online */
+ BFA_STATUS_RPORT_OFFLINE = 35, /* RPORT is not online */
+ BFA_STATUS_TGTOPEN_FAILED = 36, /* Remote SCSI target open failed */
+ BFA_STATUS_BAD_LUNS = 37, /* No valid LUNs found */
+ BFA_STATUS_IO_FAILURE = 38, /* SCSI target IO failure */
+ BFA_STATUS_NO_FABRIC = 39, /* No switched fabric present */
+ BFA_STATUS_EBADF = 40, /* Bad file descriptor */
+ BFA_STATUS_EINTR = 41, /* A signal was caught during ioctl */
+ BFA_STATUS_EIO = 42, /* I/O error */
+ BFA_STATUS_ENOTTY = 43, /* Inappropriate I/O control
+ * operation */
+ BFA_STATUS_ENXIO = 44, /* No such device or address */
+ BFA_STATUS_EFOPEN = 45, /* Failed to open file */
+ BFA_STATUS_VPORT_WWN_BP = 46, /* WWN is same as base port's WWN */
+ BFA_STATUS_PORT_NOT_DISABLED = 47, /* Port not disabled disable port
+ * first */
+ BFA_STATUS_BADFRMHDR = 48, /* Bad frame header */
+ BFA_STATUS_BADFRMSZ = 49, /* Bad frame size check and replace
+ * SFP/cable */
+ BFA_STATUS_MISSINGFRM = 50, /* Missing frame check and replace
+ * SFP/cable */
+ BFA_STATUS_LINKTIMEOUT = 51, /* Link timeout check and replace
+ * SFP/cable */
+ BFA_STATUS_NO_FCPIM_NEXUS = 52, /* No FCP Nexus exists with the
+ * rport */
+ BFA_STATUS_CHECKSUM_FAIL = 53, /* checksum failure */
+ BFA_STATUS_GZME_FAILED = 54, /* Get zone member query failed */
+ BFA_STATUS_SCSISTART_REQD = 55, /* SCSI disk require START command */
+ BFA_STATUS_IOC_FAILURE = 56, /* IOC failure - Retry, if persists
+ * contact support */
+ BFA_STATUS_INVALID_WWN = 57, /* Invalid WWN */
+ BFA_STATUS_MISMATCH = 58, /* Version mismatch */
+ BFA_STATUS_IOC_ENABLED = 59, /* IOC is already enabled */
+ BFA_STATUS_ADAPTER_ENABLED = 60, /* Adapter is not disabled disable
+ * adapter first */
+ BFA_STATUS_IOC_NON_OP = 61, /* IOC is not operational. Enable IOC
+ * and if it still fails,
+ * contact support */
+ BFA_STATUS_ADDR_MAP_FAILURE = 62, /* PCI base address not mapped
+ * in OS */
+ BFA_STATUS_SAME_NAME = 63, /* Name exists! use a different
+ * name */
+ BFA_STATUS_PENDING = 64, /* API completes asynchronously */
+ BFA_STATUS_8G_SPD = 65, /* Speed setting not valid for
+ * 8G HBA */
+ BFA_STATUS_4G_SPD = 66, /* Speed setting not valid for
+ * 4G HBA */
+ BFA_STATUS_AD_IS_ENABLE = 67, /* Adapter is already enabled */
+ BFA_STATUS_EINVAL_TOV = 68, /* Invalid path failover TOV */
+ BFA_STATUS_EINVAL_QDEPTH = 69, /* Invalid queue depth value */
+ BFA_STATUS_VERSION_FAIL = 70, /* Application/Driver version
+ * mismatch */
+ BFA_STATUS_DIAG_BUSY = 71, /* diag busy */
+ BFA_STATUS_BEACON_ON = 72, /* Port Beacon already on */
+ BFA_STATUS_BEACON_OFF = 73, /* Port Beacon already off */
+ BFA_STATUS_LBEACON_ON = 74, /* Link End-to-End Beacon already
+ * on */
+ BFA_STATUS_LBEACON_OFF = 75, /* Link End-to-End Beacon already
+ * off */
+ BFA_STATUS_PORT_NOT_INITED = 76, /* Port not initialized */
+ BFA_STATUS_RPSC_ENABLED = 77, /* Target has a valid speed */
+ BFA_STATUS_ENOFSAVE = 78, /* No saved firmware trace */
+ BFA_STATUS_BAD_FILE = 79, /* Not a valid Brocade Boot Code
+ * file */
+ BFA_STATUS_RLIM_EN = 80, /* Target rate limiting is already
+ * enabled */
+ BFA_STATUS_RLIM_DIS = 81, /* Target rate limiting is already
+ * disabled */
+ BFA_STATUS_IOC_DISABLED = 82, /* IOC is already disabled */
+ BFA_STATUS_ADAPTER_DISABLED = 83, /* Adapter is already disabled */
+ BFA_STATUS_BIOS_DISABLED = 84, /* Bios is already disabled */
+ BFA_STATUS_AUTH_ENABLED = 85, /* Authentication is already
+ * enabled */
+ BFA_STATUS_AUTH_DISABLED = 86, /* Authentication is already
+ * disabled */
+ BFA_STATUS_ERROR_TRL_ENABLED = 87, /* Target rate limiting is
+ * enabled */
+ BFA_STATUS_ERROR_QOS_ENABLED = 88, /* QoS is enabled */
+ BFA_STATUS_NO_SFP_DEV = 89, /* No SFP device check or replace SFP */
+ BFA_STATUS_MEMTEST_FAILED = 90, /* Memory test failed contact
+ * support */
+ BFA_STATUS_INVALID_DEVID = 91, /* Invalid device id provided */
+ BFA_STATUS_QOS_ENABLED = 92, /* QOS is already enabled */
+ BFA_STATUS_QOS_DISABLED = 93, /* QOS is already disabled */
+ BFA_STATUS_INCORRECT_DRV_CONFIG = 94, /* Check configuration
+ * key/value pair */
+ BFA_STATUS_REG_FAIL = 95, /* Can't read windows registry */
+ BFA_STATUS_IM_INV_CODE = 96, /* Invalid IOCTL code */
+ BFA_STATUS_IM_INV_VLAN = 97, /* Invalid VLAN ID */
+ BFA_STATUS_IM_INV_ADAPT_NAME = 98, /* Invalid adapter name */
+ BFA_STATUS_IM_LOW_RESOURCES = 99, /* Memory allocation failure in
+ * driver */
+ BFA_STATUS_IM_VLANID_IS_PVID = 100, /* Given VLAN id same as PVID */
+ BFA_STATUS_IM_VLANID_EXISTS = 101, /* Given VLAN id already exists */
+ BFA_STATUS_IM_FW_UPDATE_FAIL = 102, /* Updating firmware with new
+ * VLAN ID failed */
+ BFA_STATUS_PORTLOG_ENABLED = 103, /* Port Log is already enabled */
+ BFA_STATUS_PORTLOG_DISABLED = 104, /* Port Log is already disabled */
+ BFA_STATUS_FILE_NOT_FOUND = 105, /* Specified file could not be
+ * found */
+ BFA_STATUS_QOS_FC_ONLY = 106, /* QOS can be enabled for FC mode
+ * only */
+ BFA_STATUS_RLIM_FC_ONLY = 107, /* RATELIM can be enabled for FC mode
+ * only */
+ BFA_STATUS_CT_SPD = 108, /* Invalid speed selection for Catapult. */
+ BFA_STATUS_LEDTEST_OP = 109, /* LED test is operating */
+ BFA_STATUS_CEE_NOT_DN = 110, /* eth port is not at down state, please
+ * bring down first */
+ BFA_STATUS_10G_SPD = 111, /* Speed setting not valid for 10G HBA */
+ BFA_STATUS_IM_INV_TEAM_NAME = 112, /* Invalid team name */
+ BFA_STATUS_IM_DUP_TEAM_NAME = 113, /* Given team name already
+ * exists */
+ BFA_STATUS_IM_ADAPT_ALREADY_IN_TEAM = 114, /* Given adapter is part
+ * of another team */
+ BFA_STATUS_IM_ADAPT_HAS_VLANS = 115, /* Adapter has VLANs configured.
+ * Delete all VLANs before
+ * creating team */
+ BFA_STATUS_IM_PVID_MISMATCH = 116, /* Mismatching PVIDs configured
+ * for adapters */
+ BFA_STATUS_IM_LINK_SPEED_MISMATCH = 117, /* Mismatching link speeds
+ * configured for adapters */
+ BFA_STATUS_IM_MTU_MISMATCH = 118, /* Mismatching MTUs configured for
+ * adapters */
+ BFA_STATUS_IM_RSS_MISMATCH = 119, /* Mismatching RSS parameters
+ * configured for adapters */
+ BFA_STATUS_IM_HDS_MISMATCH = 120, /* Mismatching HDS parameters
+ * configured for adapters */
+ BFA_STATUS_IM_OFFLOAD_MISMATCH = 121, /* Mismatching offload
+ * parameters configured for
+ * adapters */
+ BFA_STATUS_IM_PORT_PARAMS = 122, /* Error setting port parameters */
+ BFA_STATUS_IM_PORT_NOT_IN_TEAM = 123, /* Port is not part of team */
+ BFA_STATUS_IM_CANNOT_REM_PRI = 124, /* Primary adapter cannot be
+ * removed. Change primary before
+ * removing */
+ BFA_STATUS_IM_MAX_PORTS_REACHED = 125, /* Exceeding maximum ports
+ * per team */
+ BFA_STATUS_IM_LAST_PORT_DELETE = 126, /* Last port in team being
+ * deleted */
+ BFA_STATUS_IM_NO_DRIVER = 127, /* IM driver is not installed */
+ BFA_STATUS_IM_MAX_VLANS_REACHED = 128, /* Exceeding maximum VLANs
+ * per port */
+ BFA_STATUS_TOMCAT_SPD_NOT_ALLOWED = 129, /* Bios speed config not
+ * allowed for CNA */
+ BFA_STATUS_NO_MINPORT_DRIVER = 130, /* Miniport driver is not
+ * loaded */
+ BFA_STATUS_CARD_TYPE_MISMATCH = 131, /* Card type mismatch */
+ BFA_STATUS_BAD_ASICBLK = 132, /* Bad ASIC block */
+ BFA_STATUS_NO_DRIVER = 133, /* Storage/Ethernet driver not loaded */
+ BFA_STATUS_INVALID_MAC = 134, /* Invalid mac address */
+ BFA_STATUS_IM_NO_VLAN = 135, /* No VLANs configured on the adapter */
+ BFA_STATUS_IM_ETH_LB_FAILED = 136, /* Ethernet loopback test failed */
+ BFA_STATUS_IM_PVID_REMOVE = 137, /* Cannot remove port vlan (PVID) */
+ BFA_STATUS_IM_PVID_EDIT = 138, /* Cannot edit port vlan (PVID) */
+ BFA_STATUS_CNA_NO_BOOT = 139, /* Boot upload not allowed for CNA */
+ BFA_STATUS_IM_PVID_NON_ZERO = 140, /* Port VLAN ID (PVID) is Set to
+ * Non-Zero Value */
+ BFA_STATUS_IM_INETCFG_LOCK_FAILED = 141, /* Acquiring Network
+ * Subsytem Lock Failed.Please
+ * try after some time */
+ BFA_STATUS_IM_GET_INETCFG_FAILED = 142, /* Acquiring Network Subsytem
+ * handle Failed. Please try
+ * after some time */
+ BFA_STATUS_IM_NOT_BOUND = 143, /* Brocade 10G Ethernet Service is not
+ * Enabled on this port */
+ BFA_STATUS_INSUFFICIENT_PERMS = 144, /* User doesn't have sufficient
+ * permissions to execute the BCU
+ * application */
+ BFA_STATUS_IM_INV_VLAN_NAME = 145, /* Invalid/Reserved Vlan name
+ * string. The name is not allowed
+ * for the normal Vlans */
+ BFA_STATUS_CMD_NOTSUPP_CNA = 146, /* Command not supported for CNA */
+ BFA_STATUS_IM_PASSTHRU_EDIT = 147, /* Can not edit passthru vlan id */
+ BFA_STATUS_IM_BIND_FAILED = 148, /*! < IM Driver bind operation
+ * failed */
+ BFA_STATUS_IM_UNBIND_FAILED = 149, /* ! < IM Driver unbind operation
+ * failed */
+ BFA_STATUS_MAX_VAL /* Unknown error code */
+};
+#define bfa_status_t enum bfa_status
+
+enum bfa_eproto_status {
+ BFA_EPROTO_BAD_ACCEPT = 0,
+ BFA_EPROTO_UNKNOWN_RSP = 1
+};
+#define bfa_eproto_status_t enum bfa_eproto_status
+
+#endif /* __BFA_DEFS_STATUS_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_tin.h b/drivers/scsi/bfa/include/defs/bfa_defs_tin.h
new file mode 100644
index 000000000000..e05a2db7abed
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_tin.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_TIN_H__
+#define __BFA_DEFS_TIN_H__
+
+#include <protocol/types.h>
+#include <protocol/fc.h>
+
+/**
+ * FCS tin states
+ */
+enum bfa_tin_state_e {
+ BFA_TIN_SM_OFFLINE = 0, /* tin is offline */
+ BFA_TIN_SM_WOS_LOGIN = 1, /* Waiting PRLI ACC/RJT from ULP */
+ BFA_TIN_SM_WFW_ONLINE = 2, /* Waiting ACK to PRLI ACC from FW */
+ BFA_TIN_SM_ONLINE = 3, /* tin login is complete */
+ BFA_TIN_SM_WIO_RELOGIN = 4, /* tin relogin is in progress */
+ BFA_TIN_SM_WIO_LOGOUT = 5, /* Processing of PRLO req from
+ * Initiator is in progress
+ */
+ BFA_TIN_SM_WOS_LOGOUT = 6, /* Processing of PRLO req from
+ * Initiator is in progress
+ */
+ BFA_TIN_SM_WIO_CLEAN = 7, /* Waiting for IO cleanup before tin
+ * is offline. This can be triggered
+ * by RPORT LOGO (rcvd/sent) or by
+ * PRLO (rcvd/sent)
+ */
+};
+
+struct bfa_prli_req_s {
+ struct fchs_s fchs;
+ struct fc_prli_s prli_payload;
+};
+
+struct bfa_prlo_req_s {
+ struct fchs_s fchs;
+ struct fc_prlo_s prlo_payload;
+};
+
+void bfa_tin_send_login_rsp(void *bfa_tin, u32 login_rsp,
+ struct fc_ls_rjt_s rjt_payload);
+void bfa_tin_send_logout_rsp(void *bfa_tin, u32 logout_rsp,
+ struct fc_ls_rjt_s rjt_payload);
+/**
+ * FCS target port statistics
+ */
+struct bfa_tin_stats_s {
+ u32 onlines; /* ITN nexus onlines (PRLI done) */
+ u32 offlines; /* ITN Nexus offlines */
+ u32 prli_req_parse_err; /* prli req parsing errors */
+ u32 prli_rsp_rjt; /* num prli rsp rejects sent */
+ u32 prli_rsp_acc; /* num prli rsp accepts sent */
+ u32 cleanup_comps; /* ITN cleanup completions */
+};
+
+/**
+ * FCS tin attributes returned in queries
+ */
+struct bfa_tin_attr_s {
+ enum bfa_tin_state_e state;
+ u8 seq_retry; /* Sequence retry supported */
+ u8 rsvd[3];
+};
+
+/**
+ * BFA TIN async event data structure for BFAL
+ */
+enum bfa_tin_aen_event {
+ BFA_TIN_AEN_ONLINE = 1, /* Target online */
+ BFA_TIN_AEN_OFFLINE = 2, /* Target offline */
+ BFA_TIN_AEN_DISCONNECT = 3, /* Target disconnected */
+};
+
+/**
+ * BFA TIN event data structure.
+ */
+struct bfa_tin_aen_data_s {
+ u16 vf_id; /* vf_id of the IT nexus */
+ u16 rsvd[3];
+ wwn_t lpwwn; /* WWN of logical port */
+ wwn_t rpwwn; /* WWN of remote(target) port */
+};
+
+/**
+ * Below APIs are needed from BFA driver
+ * Move these to BFA driver public header file?
+ */
+/* TIN rcvd new PRLI & gets bfad_tin_t ptr from driver this callback */
+void *bfad_tin_rcvd_login_req(void *bfad_tm_port, void *bfa_tin,
+ wwn_t rp_wwn, u32 rp_fcid,
+ struct bfa_prli_req_s prli_req);
+/* TIN rcvd new PRLO */
+void bfad_tin_rcvd_logout_req(void *bfad_tin, wwn_t rp_wwn, u32 rp_fcid,
+ struct bfa_prlo_req_s prlo_req);
+/* TIN is online and ready for IO */
+void bfad_tin_online(void *bfad_tin);
+/* TIN is offline and BFA driver can shutdown its upper stack */
+void bfad_tin_offline(void *bfad_tin);
+/* TIN does not need this BFA driver tin tag anymore, so can be freed */
+void bfad_tin_res_free(void *bfad_tin);
+
+#endif /* __BFA_DEFS_TIN_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h b/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h
new file mode 100644
index 000000000000..31881d218515
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_tsensor.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_TSENSOR_H__
+#define __BFA_DEFS_TSENSOR_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_types.h>
+
+/**
+ * Temperature sensor status values
+ */
+enum bfa_tsensor_status {
+ BFA_TSENSOR_STATUS_UNKNOWN = 1, /* unkown status */
+ BFA_TSENSOR_STATUS_FAULTY = 2, /* sensor is faulty */
+ BFA_TSENSOR_STATUS_BELOW_MIN = 3, /* temperature below mininum */
+ BFA_TSENSOR_STATUS_NOMINAL = 4, /* normal temperature */
+ BFA_TSENSOR_STATUS_ABOVE_MAX = 5, /* temperature above maximum */
+};
+
+/**
+ * Temperature sensor attribute
+ */
+struct bfa_tsensor_attr_s {
+ enum bfa_tsensor_status status; /* temperature sensor status */
+ u32 value; /* current temperature in celsius */
+};
+
+#endif /* __BFA_DEFS_TSENSOR_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_types.h b/drivers/scsi/bfa/include/defs/bfa_defs_types.h
new file mode 100644
index 000000000000..4348332b107a
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_types.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DEFS_TYPES_H__
+#define __BFA_DEFS_TYPES_H__
+
+#include <bfa_os_inc.h>
+
+enum bfa_boolean {
+ BFA_FALSE = 0,
+ BFA_TRUE = 1
+};
+#define bfa_boolean_t enum bfa_boolean
+
+#define BFA_STRING_32 32
+
+#endif /* __BFA_DEFS_TYPES_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_version.h b/drivers/scsi/bfa/include/defs/bfa_defs_version.h
new file mode 100644
index 000000000000..f8902a2c9aad
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_version.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#ifndef __BFA_DEFS_VERSION_H__
+#define __BFA_DEFS_VERSION_H__
+
+#define BFA_VERSION_LEN 64
+
+#endif
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_vf.h b/drivers/scsi/bfa/include/defs/bfa_defs_vf.h
new file mode 100644
index 000000000000..3235be5e9423
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_vf.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_VF_H__
+#define __BFA_DEFS_VF_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_port.h>
+#include <protocol/types.h>
+
+/**
+ * VF states
+ */
+enum bfa_vf_state {
+ BFA_VF_UNINIT = 0, /* fabric is not yet initialized */
+ BFA_VF_LINK_DOWN = 1, /* link is down */
+ BFA_VF_FLOGI = 2, /* flogi is in progress */
+ BFA_VF_AUTH = 3, /* authentication in progress */
+ BFA_VF_NOFABRIC = 4, /* fabric is not present */
+ BFA_VF_ONLINE = 5, /* login to fabric is complete */
+ BFA_VF_EVFP = 6, /* EVFP is in progress */
+ BFA_VF_ISOLATED = 7, /* port isolated due to vf_id mismatch */
+};
+
+/**
+ * VF statistics
+ */
+struct bfa_vf_stats_s {
+ u32 flogi_sent; /* Num FLOGIs sent */
+ u32 flogi_rsp_err; /* FLOGI response errors */
+ u32 flogi_acc_err; /* FLOGI accept errors */
+ u32 flogi_accepts; /* FLOGI accepts received */
+ u32 flogi_rejects; /* FLOGI rejects received */
+ u32 flogi_unknown_rsp; /* Unknown responses for FLOGI */
+ u32 flogi_alloc_wait; /* Allocation waits prior to
+ * sending FLOGI
+ */
+ u32 flogi_rcvd; /* FLOGIs received */
+ u32 flogi_rejected; /* Incoming FLOGIs rejected */
+ u32 fabric_onlines; /* Internal fabric online
+ * notification sent to other
+ * modules
+ */
+ u32 fabric_offlines; /* Internal fabric offline
+ * notification sent to other
+ * modules
+ */
+ u32 resvd;
+};
+
+/**
+ * VF attributes returned in queries
+ */
+struct bfa_vf_attr_s {
+ enum bfa_vf_state state; /* VF state */
+ u32 rsvd;
+ wwn_t fabric_name; /* fabric name */
+};
+
+#endif /* __BFA_DEFS_VF_H__ */
diff --git a/drivers/scsi/bfa/include/defs/bfa_defs_vport.h b/drivers/scsi/bfa/include/defs/bfa_defs_vport.h
new file mode 100644
index 000000000000..9f021f43b3b4
--- /dev/null
+++ b/drivers/scsi/bfa/include/defs/bfa_defs_vport.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_DEFS_VPORT_H__
+#define __BFA_DEFS_VPORT_H__
+
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_port.h>
+#include <protocol/types.h>
+
+/**
+ * VPORT states
+ */
+enum bfa_vport_state {
+ BFA_FCS_VPORT_UNINIT = 0,
+ BFA_FCS_VPORT_CREATED = 1,
+ BFA_FCS_VPORT_OFFLINE = 1,
+ BFA_FCS_VPORT_FDISC_SEND = 2,
+ BFA_FCS_VPORT_FDISC = 3,
+ BFA_FCS_VPORT_FDISC_RETRY = 4,
+ BFA_FCS_VPORT_ONLINE = 5,
+ BFA_FCS_VPORT_DELETING = 6,
+ BFA_FCS_VPORT_CLEANUP = 6,
+ BFA_FCS_VPORT_LOGO_SEND = 7,
+ BFA_FCS_VPORT_LOGO = 8,
+ BFA_FCS_VPORT_ERROR = 9,
+ BFA_FCS_VPORT_MAX_STATE,
+};
+
+/**
+ * vport statistics
+ */
+struct bfa_vport_stats_s {
+ struct bfa_port_stats_s port_stats; /* base class (port) stats */
+ /*
+ * TODO - remove
+ */
+
+ u32 fdisc_sent; /* num fdisc sent */
+ u32 fdisc_accepts; /* fdisc accepts */
+ u32 fdisc_retries; /* fdisc retries */
+ u32 fdisc_timeouts; /* fdisc timeouts */
+ u32 fdisc_rsp_err; /* fdisc response error */
+ u32 fdisc_acc_bad; /* bad fdisc accepts */
+ u32 fdisc_rejects; /* fdisc rejects */
+ u32 fdisc_unknown_rsp;
+ /*
+ *!< fdisc rsp unknown error
+ */
+ u32 fdisc_alloc_wait;/* fdisc req (fcxp)alloc wait */
+
+ u32 logo_alloc_wait;/* logo req (fcxp) alloc wait */
+ u32 logo_sent; /* logo sent */
+ u32 logo_accepts; /* logo accepts */
+ u32 logo_rejects; /* logo rejects */
+ u32 logo_rsp_err; /* logo rsp errors */
+ u32 logo_unknown_rsp;
+ /* logo rsp unknown errors */
+
+ u32 fab_no_npiv; /* fabric does not support npiv */
+
+ u32 fab_offline; /* offline events from fab SM */
+ u32 fab_online; /* online events from fab SM */
+ u32 fab_cleanup; /* cleanup request from fab SM */
+ u32 rsvd;
+};
+
+/**
+ * BFA vport attribute returned in queries
+ */
+struct bfa_vport_attr_s {
+ struct bfa_port_attr_s port_attr; /* base class (port) attributes */
+ enum bfa_vport_state vport_state; /* vport state */
+ u32 rsvd;
+};
+
+#endif /* __BFA_DEFS_VPORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb.h b/drivers/scsi/bfa/include/fcb/bfa_fcb.h
new file mode 100644
index 000000000000..2963b0bc30e7
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcb.h BFA FCS callback interfaces
+ */
+
+#ifndef __BFA_FCB_H__
+#define __BFA_FCB_H__
+
+/**
+ * fcb Main fcs callbacks
+ */
+
+void bfa_fcb_exit(struct bfad_s *bfad);
+
+
+
+#endif /* __BFA_FCB_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h
new file mode 100644
index 000000000000..a6c70aee0aa3
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_fcpim.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+* : bfad_fcpim.h - BFA FCS initiator mode remote port callbacks
+ */
+
+#ifndef __BFAD_FCB_FCPIM_H__
+#define __BFAD_FCB_FCPIM_H__
+
+struct bfad_itnim_s;
+
+/*
+ * RPIM callbacks
+ */
+
+/**
+ * Memory allocation for remote port instance. Called before PRLI is
+ * initiated to the remote target port.
+ *
+ * @param[in] bfad - driver instance
+ * @param[out] itnim - FCS remote port (IM) instance
+ * @param[out] itnim_drv - driver remote port (IM) instance
+ *
+ * @return None
+ */
+void bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim,
+ struct bfad_itnim_s **itnim_drv);
+
+/**
+ * Free remote port (IM) instance.
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] itnim_drv - driver remote port instance
+ *
+ * @return None
+ */
+void bfa_fcb_itnim_free(struct bfad_s *bfad,
+ struct bfad_itnim_s *itnim_drv);
+
+/**
+ * Notification of when login with a remote target device is complete.
+ *
+ * @param[in] itnim_drv - driver remote port instance
+ *
+ * @return None
+ */
+void bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv);
+
+/**
+ * Notification when login with the remote device is severed.
+ *
+ * @param[in] itnim_drv - driver remote port instance
+ *
+ * @return None
+ */
+void bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv);
+
+void bfa_fcb_itnim_tov_begin(struct bfad_itnim_s *itnim_drv);
+void bfa_fcb_itnim_tov(struct bfad_itnim_s *itnim_drv);
+
+#endif /* __BFAD_FCB_FCPIM_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h
new file mode 100644
index 000000000000..5fd7f986fa32
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_port.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcb_port.h BFA FCS virtual port driver interfaces
+ */
+
+#ifndef __BFA_FCB_PORT_H__
+#define __BFA_FCB_PORT_H__
+
+#include <fcb/bfa_fcb_vport.h>
+/**
+ * fcs_port_fcb FCS port driver interfaces
+ */
+
+/*
+ * Forward declarations
+ */
+struct bfad_port_s;
+
+/*
+ * Callback functions from BFA FCS to driver
+ */
+
+/**
+ * Call from FCS to driver module when a port is instantiated. The port
+ * can be a base port or a virtual port with in the base fabric or
+ * a virtual fabric.
+ *
+ * On this callback, driver is supposed to create scsi_host, scsi_tgt or
+ * network interfaces bases on ports personality/roles.
+ *
+ * base port of base fabric: vf_drv == NULL && vp_drv == NULL
+ * vport of base fabric: vf_drv == NULL && vp_drv != NULL
+ * base port of VF: vf_drv != NULL && vp_drv == NULL
+ * vport of VF: vf_drv != NULL && vp_drv != NULL
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] port - FCS port instance
+ * @param[in] roles - port roles: IM, TM, IP
+ * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF)
+ * @param[in] vp_drv - vport driver instance, NULL if base port
+ *
+ * @return None
+ */
+struct bfad_port_s *bfa_fcb_port_new(struct bfad_s *bfad,
+ struct bfa_fcs_port_s *port,
+ enum bfa_port_role roles, struct bfad_vf_s *vf_drv,
+ struct bfad_vport_s *vp_drv);
+
+/**
+ * Call from FCS to driver module when a port is deleted. The port
+ * can be a base port or a virtual port with in the base fabric or
+ * a virtual fabric.
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] roles - port roles: IM, TM, IP
+ * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF)
+ * @param[in] vp_drv - vport driver instance, NULL if base port
+ *
+ * @return None
+ */
+void bfa_fcb_port_delete(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv);
+
+/**
+ * Notification when port transitions to ONLINE state.
+ *
+ * Online notification is a logical link up for the local port. This
+ * notification is sent after a successfull FLOGI, or a successful
+ * link initialization in proviate-loop or N2N topologies.
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] roles - port roles: IM, TM, IP
+ * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF)
+ * @param[in] vp_drv - vport driver instance, NULL if base port
+ *
+ * @return None
+ */
+void bfa_fcb_port_online(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv);
+
+/**
+ * Notification when port transitions to OFFLINE state.
+ *
+ * Offline notification is a logical link down for the local port.
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] roles - port roles: IM, TM, IP
+ * @param[in] vf_drv - VF driver instance, NULL if base fabric (no VF)
+ * @param[in] vp_drv - vport driver instance, NULL if base port
+ *
+ * @return None
+ */
+void bfa_fcb_port_offline(struct bfad_s *bfad, enum bfa_port_role roles,
+ struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv);
+
+
+#endif /* __BFA_FCB_PORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h
new file mode 100644
index 000000000000..e0261bb6d1c1
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_rport.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcb_rport.h BFA FCS rport driver interfaces
+ */
+
+#ifndef __BFA_FCB_RPORT_H__
+#define __BFA_FCB_RPORT_H__
+
+/**
+ * fcs_rport_fcb Remote port driver interfaces
+ */
+
+
+struct bfad_rport_s;
+
+/*
+ * Callback functions from BFA FCS to driver
+ */
+
+/**
+ * Completion callback for bfa_fcs_rport_add().
+ *
+ * @param[in] rport_drv - driver instance of rport
+ *
+ * @return None
+ */
+void bfa_fcb_rport_add(struct bfad_rport_s *rport_drv);
+
+/**
+ * Completion callback for bfa_fcs_rport_remove().
+ *
+ * @param[in] rport_drv - driver instance of rport
+ *
+ * @return None
+ */
+void bfa_fcb_rport_remove(struct bfad_rport_s *rport_drv);
+
+/**
+ * Call to allocate a rport instance.
+ *
+ * @param[in] bfad - driver instance
+ * @param[out] rport - BFA FCS instance of rport
+ * @param[out] rport_drv - driver instance of rport
+ *
+ * @retval BFA_STATUS_OK - successfully allocated
+ * @retval BFA_STATUS_ENOMEM - cannot allocate
+ */
+bfa_status_t bfa_fcb_rport_alloc(struct bfad_s *bfad,
+ struct bfa_fcs_rport_s **rport,
+ struct bfad_rport_s **rport_drv);
+
+/**
+ * Call to free rport memory resources.
+ *
+ * @param[in] bfad - driver instance
+ * @param[in] rport_drv - driver instance of rport
+ *
+ * @return None
+ */
+void bfa_fcb_rport_free(struct bfad_s *bfad, struct bfad_rport_s **rport_drv);
+
+
+
+#endif /* __BFA_FCB_RPORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h
new file mode 100644
index 000000000000..cfd3fac0a4e2
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_vf.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcb_vf.h BFA FCS virtual fabric driver interfaces
+ */
+
+#ifndef __BFA_FCB_VF_H__
+#define __BFA_FCB_VF_H__
+
+/**
+ * fcs_vf_fcb Virtual fabric driver intrefaces
+ */
+
+
+struct bfad_vf_s;
+
+/*
+ * Callback functions from BFA FCS to driver
+ */
+
+/**
+ * Completion callback for bfa_fcs_vf_stop().
+ *
+ * @param[in] vf_drv - driver instance of vf
+ *
+ * @return None
+ */
+void bfa_fcb_vf_stop(struct bfad_vf_s *vf_drv);
+
+
+
+#endif /* __BFA_FCB_VF_H__ */
diff --git a/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h
new file mode 100644
index 000000000000..a39f474c2fcf
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcb/bfa_fcb_vport.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcb_vport.h BFA FCS virtual port driver interfaces
+ */
+
+#ifndef __BFA_FCB_VPORT_H__
+#define __BFA_FCB_VPORT_H__
+
+/**
+ * fcs_vport_fcb Virtual port driver interfaces
+ */
+
+
+struct bfad_vport_s;
+
+/*
+ * Callback functions from BFA FCS to driver
+ */
+
+/**
+ * Completion callback for bfa_fcs_vport_delete().
+ *
+ * @param[in] vport_drv - driver instance of vport
+ *
+ * @return None
+ */
+void bfa_fcb_vport_delete(struct bfad_vport_s *vport_drv);
+
+
+
+#endif /* __BFA_FCB_VPORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs.h b/drivers/scsi/bfa/include/fcs/bfa_fcs.h
new file mode 100644
index 000000000000..627669c65546
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_FCS_H__
+#define __BFA_FCS_H__
+
+#include <cs/bfa_debug.h>
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_version.h>
+#include <bfa.h>
+#include <fcs/bfa_fcs_fabric.h>
+
+#define BFA_FCS_OS_STR_LEN 64
+
+struct bfa_fcs_stats_s {
+ struct {
+ u32 untagged; /* untagged receive frames */
+ u32 tagged; /* tagged receive frames */
+ u32 vfid_unknown; /* VF id is unknown */
+ } uf;
+};
+
+struct bfa_fcs_driver_info_s {
+ u8 version[BFA_VERSION_LEN]; /* Driver Version */
+ u8 host_machine_name[BFA_FCS_OS_STR_LEN];
+ u8 host_os_name[BFA_FCS_OS_STR_LEN]; /* OS name and version */
+ u8 host_os_patch[BFA_FCS_OS_STR_LEN];/* patch or service pack */
+ u8 os_device_name[BFA_FCS_OS_STR_LEN]; /* Driver Device Name */
+};
+
+struct bfa_fcs_s {
+ struct bfa_s *bfa; /* corresponding BFA bfa instance */
+ struct bfad_s *bfad; /* corresponding BDA driver instance */
+ struct bfa_log_mod_s *logm; /* driver logging module instance */
+ struct bfa_trc_mod_s *trcmod; /* tracing module */
+ struct bfa_aen_s *aen; /* aen component */
+ bfa_boolean_t vf_enabled; /* VF mode is enabled */
+ bfa_boolean_t min_cfg; /* min cfg enabled/disabled */
+ u16 port_vfid; /* port default VF ID */
+ struct bfa_fcs_driver_info_s driver_info;
+ struct bfa_fcs_fabric_s fabric; /* base fabric state machine */
+ struct bfa_fcs_stats_s stats; /* FCS statistics */
+ struct bfa_wc_s wc; /* waiting counter */
+};
+
+/*
+ * bfa fcs API functions
+ */
+void bfa_fcs_init(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad,
+ bfa_boolean_t min_cfg);
+void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs,
+ struct bfa_fcs_driver_info_s *driver_info);
+void bfa_fcs_exit(struct bfa_fcs_s *fcs);
+void bfa_fcs_trc_init(struct bfa_fcs_s *fcs, struct bfa_trc_mod_s *trcmod);
+void bfa_fcs_log_init(struct bfa_fcs_s *fcs, struct bfa_log_mod_s *logmod);
+void bfa_fcs_aen_init(struct bfa_fcs_s *fcs, struct bfa_aen_s *aen);
+void bfa_fcs_start(struct bfa_fcs_s *fcs);
+
+#endif /* __BFA_FCS_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h
new file mode 100644
index 000000000000..28c4c9ff08b3
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_auth.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_FCS_AUTH_H__
+#define __BFA_FCS_AUTH_H__
+
+struct bfa_fcs_s;
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_auth.h>
+#include <defs/bfa_defs_vf.h>
+#include <cs/bfa_q.h>
+#include <cs/bfa_sm.h>
+#include <defs/bfa_defs_pport.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <protocol/fc_sp.h>
+
+struct bfa_fcs_fabric_s;
+
+
+
+struct bfa_fcs_auth_s {
+ bfa_sm_t sm; /* state machine */
+ bfa_boolean_t policy; /* authentication enabled/disabled */
+ enum bfa_auth_status status; /* authentication status */
+ enum auth_rjt_codes rjt_code; /* auth reject status */
+ enum auth_rjt_code_exps rjt_code_exp; /* auth reject reason */
+ enum bfa_auth_algo algo; /* Authentication algorithm */
+ struct bfa_auth_stats_s stats; /* Statistics */
+ enum auth_dh_gid group; /* DH(diffie-hellman) Group */
+ enum bfa_auth_secretsource source; /* Secret source */
+ char secret[BFA_AUTH_SECRET_STRING_LEN];
+ /* secret string */
+ u8 secret_len;
+ /* secret string length */
+ u8 nretries;
+ /* number of retries */
+ struct bfa_fcs_fabric_s *fabric;/* pointer to fabric */
+ u8 sentcode; /* pointer to response data */
+ u8 *response; /* pointer to response data */
+ struct bfa_timer_s delay_timer; /* delay timer */
+ struct bfa_fcxp_s *fcxp; /* pointer to fcxp */
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+};
+
+/**
+ * bfa fcs authentication public functions
+ */
+bfa_status_t bfa_fcs_auth_get_attr(struct bfa_fcs_s *port,
+ struct bfa_auth_attr_s *attr);
+bfa_status_t bfa_fcs_auth_set_policy(struct bfa_fcs_s *port,
+ bfa_boolean_t policy);
+enum bfa_auth_status bfa_fcs_auth_get_status(struct bfa_fcs_s *port);
+bfa_status_t bfa_fcs_auth_set_algo(struct bfa_fcs_s *port,
+ enum bfa_auth_algo algo);
+bfa_status_t bfa_fcs_auth_get_stats(struct bfa_fcs_s *port,
+ struct bfa_auth_stats_s *stats);
+bfa_status_t bfa_fcs_auth_set_dh_group(struct bfa_fcs_s *port, int group);
+bfa_status_t bfa_fcs_auth_set_secretstring(struct bfa_fcs_s *port,
+ char *secret);
+bfa_status_t bfa_fcs_auth_set_secretstring_encrypt(struct bfa_fcs_s *port,
+ u32 secret[], u32 len);
+bfa_status_t bfa_fcs_auth_set_secretsource(struct bfa_fcs_s *port,
+ enum bfa_auth_secretsource src);
+bfa_status_t bfa_fcs_auth_reset_stats(struct bfa_fcs_s *port);
+bfa_status_t bfa_fcs_auth_reinit(struct bfa_fcs_s *port);
+
+#endif /* __BFA_FCS_AUTH_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h
new file mode 100644
index 000000000000..08b79d5e46f3
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fabric.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_FCS_FABRIC_H__
+#define __BFA_FCS_FABRIC_H__
+
+struct bfa_fcs_s;
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_vf.h>
+#include <cs/bfa_q.h>
+#include <cs/bfa_sm.h>
+#include <defs/bfa_defs_pport.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <protocol/fc_sp.h>
+#include <fcs/bfa_fcs_auth.h>
+
+/*
+ * forward declaration
+ */
+struct bfad_vf_s;
+
+enum bfa_fcs_fabric_type {
+ BFA_FCS_FABRIC_UNKNOWN = 0,
+ BFA_FCS_FABRIC_SWITCHED = 1,
+ BFA_FCS_FABRIC_PLOOP = 2,
+ BFA_FCS_FABRIC_N2N = 3,
+};
+
+
+struct bfa_fcs_fabric_s {
+ struct list_head qe; /* queue element */
+ bfa_sm_t sm; /* state machine */
+ struct bfa_fcs_s *fcs; /* FCS instance */
+ struct bfa_fcs_port_s bport; /* base logical port */
+ enum bfa_fcs_fabric_type fab_type; /* fabric type */
+ enum bfa_pport_type oper_type; /* current link topology */
+ u8 is_vf; /* is virtual fabric? */
+ u8 is_npiv; /* is NPIV supported ? */
+ u8 is_auth; /* is Security/Auth supported ? */
+ u16 bb_credit; /* BB credit from fabric */
+ u16 vf_id; /* virtual fabric ID */
+ u16 num_vports; /* num vports */
+ u16 rsvd;
+ struct list_head vport_q; /* queue of virtual ports */
+ struct list_head vf_q; /* queue of virtual fabrics */
+ struct bfad_vf_s *vf_drv; /* driver vf structure */
+ struct bfa_timer_s link_timer; /* Link Failure timer. Vport */
+ wwn_t fabric_name; /* attached fabric name */
+ bfa_boolean_t auth_reqd; /* authentication required */
+ struct bfa_timer_s delay_timer; /* delay timer */
+ union {
+ u16 swp_vfid;/* switch port VF id */
+ } event_arg;
+ struct bfa_fcs_auth_s auth; /* authentication config */
+ struct bfa_wc_s wc; /* wait counter for delete */
+ struct bfa_vf_stats_s stats; /* fabric/vf stats */
+ struct bfa_lps_s *lps; /* lport login services */
+ u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; /* attached
+ * fabric's ip addr
+ */
+};
+
+#define bfa_fcs_fabric_npiv_capable(__f) ((__f)->is_npiv)
+#define bfa_fcs_fabric_is_switched(__f) \
+ ((__f)->fab_type == BFA_FCS_FABRIC_SWITCHED)
+
+/**
+ * The design calls for a single implementation of base fabric and vf.
+ */
+#define bfa_fcs_vf_t struct bfa_fcs_fabric_s
+
+struct bfa_vf_event_s {
+ u32 undefined;
+};
+
+/**
+ * bfa fcs vf public functions
+ */
+bfa_status_t bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id);
+bfa_status_t bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs);
+bfa_status_t bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs,
+ u16 vf_id, struct bfa_port_cfg_s *port_cfg,
+ struct bfad_vf_s *vf_drv);
+bfa_status_t bfa_fcs_vf_delete(bfa_fcs_vf_t *vf);
+void bfa_fcs_vf_start(bfa_fcs_vf_t *vf);
+bfa_status_t bfa_fcs_vf_stop(bfa_fcs_vf_t *vf);
+void bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs);
+void bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs);
+void bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr);
+void bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf,
+ struct bfa_vf_stats_s *vf_stats);
+void bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf);
+void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports);
+bfa_fcs_vf_t *bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id);
+struct bfad_vf_s *bfa_fcs_vf_get_drv_vf(bfa_fcs_vf_t *vf);
+
+#endif /* __BFA_FCS_FABRIC_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h
new file mode 100644
index 000000000000..e719f2c3eb35
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fcpim.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcs_fcpim.h BFA FCS FCP Initiator Mode interfaces/defines.
+ */
+
+#ifndef __BFA_FCS_FCPIM_H__
+#define __BFA_FCS_FCPIM_H__
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_itnim.h>
+#include <fcs/bfa_fcs.h>
+#include <fcs/bfa_fcs_rport.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <bfa_fcpim.h>
+
+/*
+ * forward declarations
+ */
+struct bfad_itnim_s;
+
+struct bfa_fcs_itnim_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_fcs_rport_s *rport; /* parent remote rport */
+ struct bfad_itnim_s *itnim_drv; /* driver peer instance */
+ struct bfa_fcs_s *fcs; /* fcs instance */
+ struct bfa_timer_s timer; /* timer functions */
+ struct bfa_itnim_s *bfa_itnim; /* BFA itnim struct */
+ bfa_boolean_t seq_rec; /* seq recovery support */
+ bfa_boolean_t rec_support; /* REC supported */
+ bfa_boolean_t conf_comp; /* FCP_CONF support */
+ bfa_boolean_t task_retry_id; /* task retry id supp */
+ struct bfa_fcxp_wqe_s fcxp_wqe; /* wait qelem for fcxp */
+ struct bfa_fcxp_s *fcxp; /* FCXP in use */
+ struct bfa_itnim_stats_s stats; /* itn statistics */
+};
+
+
+static inline struct bfad_port_s *
+bfa_fcs_itnim_get_drvport(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->port->bfad_port;
+}
+
+
+static inline struct bfa_fcs_port_s *
+bfa_fcs_itnim_get_port(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->port;
+}
+
+
+static inline wwn_t
+bfa_fcs_itnim_get_nwwn(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->nwwn;
+}
+
+
+static inline wwn_t
+bfa_fcs_itnim_get_pwwn(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->pwwn;
+}
+
+
+static inline u32
+bfa_fcs_itnim_get_fcid(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->pid;
+}
+
+
+static inline u32
+bfa_fcs_itnim_get_maxfrsize(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->maxfrsize;
+}
+
+
+static inline enum fc_cos
+bfa_fcs_itnim_get_cos(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->rport->fc_cos;
+}
+
+
+static inline struct bfad_itnim_s *
+bfa_fcs_itnim_get_drvitn(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->itnim_drv;
+}
+
+
+static inline struct bfa_itnim_s *
+bfa_fcs_itnim_get_halitn(struct bfa_fcs_itnim_s *itnim)
+{
+ return itnim->bfa_itnim;
+}
+
+/**
+ * bfa fcs FCP Initiator mode API functions
+ */
+void bfa_fcs_itnim_get_attr(struct bfa_fcs_itnim_s *itnim,
+ struct bfa_itnim_attr_s *attr);
+void bfa_fcs_itnim_get_stats(struct bfa_fcs_itnim_s *itnim,
+ struct bfa_itnim_stats_s *stats);
+struct bfa_fcs_itnim_s *bfa_fcs_itnim_lookup(struct bfa_fcs_port_s *port,
+ wwn_t rpwwn);
+bfa_status_t bfa_fcs_itnim_attr_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
+ struct bfa_itnim_attr_s *attr);
+bfa_status_t bfa_fcs_itnim_stats_get(struct bfa_fcs_port_s *port, wwn_t rpwwn,
+ struct bfa_itnim_stats_s *stats);
+bfa_status_t bfa_fcs_itnim_stats_clear(struct bfa_fcs_port_s *port,
+ wwn_t rpwwn);
+#endif /* __BFA_FCS_FCPIM_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h
new file mode 100644
index 000000000000..4441fffc9c82
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_fdmi.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcs_fdmi.h BFA fcs fdmi module public interface
+ */
+
+#ifndef __BFA_FCS_FDMI_H__
+#define __BFA_FCS_FDMI_H__
+#include <bfa_os_inc.h>
+#include <protocol/fdmi.h>
+
+#define BFA_FCS_FDMI_SUPORTED_SPEEDS (FDMI_TRANS_SPEED_1G | \
+ FDMI_TRANS_SPEED_2G | \
+ FDMI_TRANS_SPEED_4G | \
+ FDMI_TRANS_SPEED_8G)
+
+/*
+* HBA Attribute Block : BFA internal representation. Note : Some variable
+* sizes have been trimmed to suit BFA For Ex : Model will be "Brocade". Based
+ * on this the size has been reduced to 16 bytes from the standard's 64 bytes.
+ */
+struct bfa_fcs_fdmi_hba_attr_s {
+ wwn_t node_name;
+ u8 manufacturer[64];
+ u8 serial_num[64];
+ u8 model[16];
+ u8 model_desc[256];
+ u8 hw_version[8];
+ u8 driver_version[8];
+ u8 option_rom_ver[BFA_VERSION_LEN];
+ u8 fw_version[8];
+ u8 os_name[256];
+ u32 max_ct_pyld;
+};
+
+/*
+ * Port Attribute Block
+ */
+struct bfa_fcs_fdmi_port_attr_s {
+ u8 supp_fc4_types[32]; /* supported FC4 types */
+ u32 supp_speed; /* supported speed */
+ u32 curr_speed; /* current Speed */
+ u32 max_frm_size; /* max frame size */
+ u8 os_device_name[256]; /* OS device Name */
+ u8 host_name[256]; /* host name */
+};
+
+#endif /* __BFA_FCS_FDMI_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h
new file mode 100644
index 000000000000..967ceb0eb074
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_lport.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcs_port.h BFA fcs port module public interface
+ */
+
+#ifndef __BFA_FCS_PORT_H__
+#define __BFA_FCS_PORT_H__
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_pport.h>
+#include <defs/bfa_defs_rport.h>
+#include <cs/bfa_q.h>
+#include <bfa_svc.h>
+#include <cs/bfa_wc.h>
+
+struct bfa_fcs_s;
+struct bfa_fcs_fabric_s;
+
+/*
+* @todo : need to move to a global config file.
+ * Maximum Vports supported per physical port or vf.
+ */
+#define BFA_FCS_MAX_VPORTS_SUPP_CB 255
+#define BFA_FCS_MAX_VPORTS_SUPP_CT 191
+
+/*
+* @todo : need to move to a global config file.
+ * Maximum Rports supported per port (physical/logical).
+ */
+#define BFA_FCS_MAX_RPORTS_SUPP 256 /* @todo : tentative value */
+
+
+struct bfa_fcs_port_ns_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_timer_s timer;
+ struct bfa_fcs_port_s *port; /* parent port */
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+};
+
+
+struct bfa_fcs_port_scn_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_timer_s timer;
+ struct bfa_fcs_port_s *port; /* parent port */
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+};
+
+
+struct bfa_fcs_port_fdmi_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_timer_s timer;
+ struct bfa_fcs_port_ms_s *ms; /* parent ms */
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+ u8 retry_cnt; /* retry count */
+ u8 rsvd[3];
+};
+
+
+struct bfa_fcs_port_ms_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_timer_s timer;
+ struct bfa_fcs_port_s *port; /* parent port */
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+ struct bfa_fcs_port_fdmi_s fdmi; /* FDMI component of MS */
+ u8 retry_cnt; /* retry count */
+ u8 rsvd[3];
+};
+
+
+struct bfa_fcs_port_fab_s {
+ struct bfa_fcs_port_ns_s ns; /* NS component of port */
+ struct bfa_fcs_port_scn_s scn; /* scn component of port */
+ struct bfa_fcs_port_ms_s ms; /* MS component of port */
+};
+
+
+
+#define MAX_ALPA_COUNT 127
+
+struct bfa_fcs_port_loop_s {
+ u8 num_alpa; /* Num of ALPA entries in the map */
+ u8 alpa_pos_map[MAX_ALPA_COUNT]; /* ALPA Positional
+ *Map */
+ struct bfa_fcs_port_s *port; /* parent port */
+};
+
+
+
+struct bfa_fcs_port_n2n_s {
+ u32 rsvd;
+ u16 reply_oxid; /* ox_id from the req flogi to be
+ *used in flogi acc */
+ wwn_t rem_port_wwn; /* Attached port's wwn */
+};
+
+
+union bfa_fcs_port_topo_u {
+ struct bfa_fcs_port_fab_s pfab;
+ struct bfa_fcs_port_loop_s ploop;
+ struct bfa_fcs_port_n2n_s pn2n;
+};
+
+
+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_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 */
+ 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 */
+ struct bfad_port_s *bfad_port; /* driver peer instance */
+ struct bfa_fcs_vport_s *vport; /* NULL for base ports */
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_fcxp_wqe_s fcxp_wqe;
+ struct bfa_port_stats_s stats;
+ struct bfa_wc_s wc; /* waiting counter for events */
+};
+
+#define bfa_fcs_lport_t struct bfa_fcs_port_s
+
+/**
+ * Symbolic Name related defines
+ * Total bytes 255.
+ * Physical Port's symbolic name 128 bytes.
+ * For Vports, Vport's symbolic name is appended to the Physical port's
+ * Symbolic Name.
+ *
+ * Physical Port's symbolic name Format : (Total 128 bytes)
+ * Adapter Model number/name : 12 bytes
+ * Driver Version : 10 bytes
+ * Host Machine Name : 30 bytes
+ * Host OS Info : 48 bytes
+ * Host OS PATCH Info : 16 bytes
+ * ( remaining 12 bytes reserved to be used for separator)
+ */
+#define BFA_FCS_PORT_SYMBNAME_SEPARATOR " | "
+
+#define BFA_FCS_PORT_SYMBNAME_MODEL_SZ 12
+#define BFA_FCS_PORT_SYMBNAME_VERSION_SZ 10
+#define BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ 30
+#define BFA_FCS_PORT_SYMBNAME_OSINFO_SZ 48
+#define BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ 16
+
+/**
+ * Get FC port ID for a logical port.
+ */
+#define bfa_fcs_port_get_fcid(_lport) ((_lport)->pid)
+#define bfa_fcs_port_get_pwwn(_lport) ((_lport)->port_cfg.pwwn)
+#define bfa_fcs_port_get_nwwn(_lport) ((_lport)->port_cfg.nwwn)
+#define bfa_fcs_port_get_psym_name(_lport) ((_lport)->port_cfg.sym_name)
+#define bfa_fcs_port_is_initiator(_lport) \
+ ((_lport)->port_cfg.roles & BFA_PORT_ROLE_FCP_IM)
+#define bfa_fcs_port_is_target(_lport) \
+ ((_lport)->port_cfg.roles & BFA_PORT_ROLE_FCP_TM)
+#define bfa_fcs_port_get_nrports(_lport) \
+ ((_lport) ? (_lport)->num_rports : 0)
+
+static inline struct bfad_port_s *
+bfa_fcs_port_get_drvport(struct bfa_fcs_port_s *port)
+{
+ return port->bfad_port;
+}
+
+
+#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_ipaddr(_lport) \
+ ((_lport)->fabric->fabric_ip_addr)
+
+/**
+ * bfa fcs port public functions
+ */
+void 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);
+void bfa_fcs_port_get_rports(struct bfa_fcs_port_s *port,
+ wwn_t rport_wwns[], int *nrports);
+
+wwn_t bfa_fcs_port_get_rport(struct bfa_fcs_port_s *port, wwn_t wwn,
+ int index, int nrports, bfa_boolean_t bwwn);
+
+struct bfa_fcs_port_s *bfa_fcs_lookup_port(struct bfa_fcs_s *fcs,
+ u16 vf_id, wwn_t lpwwn);
+
+void bfa_fcs_port_get_info(struct bfa_fcs_port_s *port,
+ struct bfa_port_info_s *port_info);
+void bfa_fcs_port_get_attr(struct bfa_fcs_port_s *port,
+ struct bfa_port_attr_s *port_attr);
+void bfa_fcs_port_get_stats(struct bfa_fcs_port_s *fcs_port,
+ struct bfa_port_stats_s *port_stats);
+void bfa_fcs_port_clear_stats(struct bfa_fcs_port_s *fcs_port);
+enum bfa_pport_speed bfa_fcs_port_get_rport_max_speed(
+ struct bfa_fcs_port_s *port);
+void bfa_fcs_port_enable_ipfc_roles(struct bfa_fcs_port_s *fcs_port);
+void bfa_fcs_port_disable_ipfc_roles(struct bfa_fcs_port_s *fcs_port);
+
+#endif /* __BFA_FCS_PORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h
new file mode 100644
index 000000000000..702b95b76c2d
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_rport.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __BFA_FCS_RPORT_H__
+#define __BFA_FCS_RPORT_H__
+
+#include <defs/bfa_defs_status.h>
+#include <cs/bfa_q.h>
+#include <fcs/bfa_fcs.h>
+#include <defs/bfa_defs_rport.h>
+
+#define BFA_FCS_RPORT_DEF_DEL_TIMEOUT 90 /* in secs */
+/*
+ * forward declarations
+ */
+struct bfad_rport_s;
+
+struct bfa_fcs_itnim_s;
+struct bfa_fcs_tin_s;
+struct bfa_fcs_iprp_s;
+
+/* Rport Features (RPF) */
+struct bfa_fcs_rpf_s {
+ bfa_sm_t sm; /* state machine */
+ struct bfa_fcs_rport_s *rport; /* parent rport */
+ struct bfa_timer_s timer; /* general purpose timer */
+ struct bfa_fcxp_s *fcxp; /* FCXP needed for discarding */
+ struct bfa_fcxp_wqe_s fcxp_wqe; /* fcxp wait queue element */
+ int rpsc_retries; /* max RPSC retry attempts */
+ enum bfa_pport_speed rpsc_speed; /* Current Speed from RPSC.
+ * O if RPSC fails */
+ enum bfa_pport_speed assigned_speed; /* Speed assigned by the user.
+ * will be used if RPSC is not
+ * supported by the rport */
+};
+
+struct bfa_fcs_rport_s {
+ struct list_head qe; /* used by port/vport */
+ struct bfa_fcs_port_s *port; /* parent FCS port */
+ struct bfa_fcs_s *fcs; /* fcs instance */
+ struct bfad_rport_s *rp_drv; /* driver peer instance */
+ u32 pid; /* port ID of rport */
+ u16 maxfrsize; /* maximum frame size */
+ u16 reply_oxid; /* OX_ID of inbound requests */
+ enum fc_cos fc_cos; /* FC classes of service supp */
+ bfa_boolean_t cisc; /* CISC capable device */
+ wwn_t pwwn; /* port wwn of rport */
+ wwn_t nwwn; /* node wwn of rport */
+ struct bfa_rport_symname_s psym_name; /* port symbolic name */
+ bfa_sm_t sm; /* state machine */
+ struct bfa_timer_s timer; /* general purpose timer */
+ struct bfa_fcs_itnim_s *itnim; /* ITN initiator mode role */
+ struct bfa_fcs_tin_s *tin; /* ITN initiator mode role */
+ struct bfa_fcs_iprp_s *iprp; /* IP/FC role */
+ struct bfa_rport_s *bfa_rport; /* BFA Rport */
+ struct bfa_fcxp_s *fcxp; /* FCXP needed for discarding */
+ int plogi_retries; /* max plogi retry attempts */
+ int ns_retries; /* max NS query retry attempts */
+ struct bfa_fcxp_wqe_s fcxp_wqe; /* fcxp wait queue element */
+ struct bfa_rport_stats_s stats; /* rport stats */
+ enum bfa_rport_function scsi_function; /* Initiator/Target */
+ struct bfa_fcs_rpf_s rpf; /* Rport features module */
+};
+
+static inline struct bfa_rport_s *
+bfa_fcs_rport_get_halrport(struct bfa_fcs_rport_s *rport)
+{
+ return rport->bfa_rport;
+}
+
+/**
+ * bfa fcs rport API functions
+ */
+bfa_status_t bfa_fcs_rport_add(struct bfa_fcs_port_s *port, wwn_t *pwwn,
+ struct bfa_fcs_rport_s *rport,
+ struct bfad_rport_s *rport_drv);
+bfa_status_t bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport);
+void bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
+ struct bfa_rport_attr_s *attr);
+void bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport,
+ struct bfa_rport_stats_s *stats);
+void bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport);
+struct bfa_fcs_rport_s *bfa_fcs_rport_lookup(struct bfa_fcs_port_s *port,
+ wwn_t rpwwn);
+struct bfa_fcs_rport_s *bfa_fcs_rport_lookup_by_nwwn(
+ struct bfa_fcs_port_s *port, wwn_t rnwwn);
+void bfa_fcs_rport_set_del_timeout(u8 rport_tmo);
+void bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport,
+ enum bfa_pport_speed speed);
+#endif /* __BFA_FCS_RPORT_H__ */
diff --git a/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h
new file mode 100644
index 000000000000..cd33f2cd5c34
--- /dev/null
+++ b/drivers/scsi/bfa/include/fcs/bfa_fcs_vport.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcs_vport.h BFA fcs vport module public interface
+ */
+
+#ifndef __BFA_FCS_VPORT_H__
+#define __BFA_FCS_VPORT_H__
+
+#include <defs/bfa_defs_status.h>
+#include <defs/bfa_defs_port.h>
+#include <defs/bfa_defs_vport.h>
+#include <fcs/bfa_fcs.h>
+#include <fcb/bfa_fcb_vport.h>
+
+struct bfa_fcs_vport_s {
+ struct list_head qe; /* queue elem */
+ bfa_sm_t sm; /* state machine */
+ bfa_fcs_lport_t lport; /* logical port */
+ struct bfa_timer_s timer; /* general purpose timer */
+ struct bfad_vport_s *vport_drv; /* Driver private */
+ struct bfa_vport_stats_s vport_stats; /* vport statistics */
+ struct bfa_lps_s *lps; /* Lport login service */
+ int fdisc_retries;
+};
+
+#define bfa_fcs_vport_get_port(vport) \
+ ((struct bfa_fcs_port_s *)(&vport->port))
+
+/**
+ * bfa fcs vport public functions
+ */
+bfa_status_t bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport,
+ struct bfa_fcs_s *fcs, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg,
+ struct bfad_vport_s *vport_drv);
+bfa_status_t bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport);
+bfa_status_t bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport);
+bfa_status_t bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport);
+void bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport,
+ struct bfa_vport_attr_s *vport_attr);
+void bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport,
+ struct bfa_vport_stats_s *vport_stats);
+void bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport);
+struct bfa_fcs_vport_s *bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs,
+ u16 vf_id, wwn_t vpwwn);
+
+#endif /* __BFA_FCS_VPORT_H__ */
diff --git a/drivers/scsi/bfa/include/log/bfa_log_fcs.h b/drivers/scsi/bfa/include/log/bfa_log_fcs.h
new file mode 100644
index 000000000000..b6f5df8827f8
--- /dev/null
+++ b/drivers/scsi/bfa/include/log/bfa_log_fcs.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/*
+ * messages define for FCS Module
+ */
+#ifndef __BFA_LOG_FCS_H__
+#define __BFA_LOG_FCS_H__
+#include <cs/bfa_log.h>
+#define BFA_LOG_FCS_FABRIC_NOSWITCH \
+ (((u32) BFA_LOG_FCS_ID << BFA_LOG_MODID_OFFSET) | 1)
+#define BFA_LOG_FCS_FABRIC_ISOLATED \
+ (((u32) BFA_LOG_FCS_ID << BFA_LOG_MODID_OFFSET) | 2)
+#endif
diff --git a/drivers/scsi/bfa/include/log/bfa_log_hal.h b/drivers/scsi/bfa/include/log/bfa_log_hal.h
new file mode 100644
index 000000000000..0412aea2ec30
--- /dev/null
+++ b/drivers/scsi/bfa/include/log/bfa_log_hal.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/* messages define for HAL Module */
+#ifndef __BFA_LOG_HAL_H__
+#define __BFA_LOG_HAL_H__
+#include <cs/bfa_log.h>
+#define BFA_LOG_HAL_ASSERT \
+ (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 1)
+#define BFA_LOG_HAL_HEARTBEAT_FAILURE \
+ (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 2)
+#define BFA_LOG_HAL_FCPIM_PARM_INVALID \
+ (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 3)
+#define BFA_LOG_HAL_SM_ASSERT \
+ (((u32) BFA_LOG_HAL_ID << BFA_LOG_MODID_OFFSET) | 4)
+#endif
diff --git a/drivers/scsi/bfa/include/log/bfa_log_linux.h b/drivers/scsi/bfa/include/log/bfa_log_linux.h
new file mode 100644
index 000000000000..317c0547ee16
--- /dev/null
+++ b/drivers/scsi/bfa/include/log/bfa_log_linux.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/* messages define for LINUX Module */
+#ifndef __BFA_LOG_LINUX_H__
+#define __BFA_LOG_LINUX_H__
+#include <cs/bfa_log.h>
+#define BFA_LOG_LINUX_DEVICE_CLAIMED \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 1)
+#define BFA_LOG_LINUX_HASH_INIT_FAILED \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 2)
+#define BFA_LOG_LINUX_SYSFS_FAILED \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 3)
+#define BFA_LOG_LINUX_MEM_ALLOC_FAILED \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 4)
+#define BFA_LOG_LINUX_DRIVER_REGISTRATION_FAILED \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 5)
+#define BFA_LOG_LINUX_ITNIM_FREE \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 6)
+#define BFA_LOG_LINUX_ITNIM_ONLINE \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 7)
+#define BFA_LOG_LINUX_ITNIM_OFFLINE \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 8)
+#define BFA_LOG_LINUX_SCSI_HOST_FREE \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 9)
+#define BFA_LOG_LINUX_SCSI_ABORT \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 10)
+#define BFA_LOG_LINUX_SCSI_ABORT_COMP \
+ (((u32) BFA_LOG_LINUX_ID << BFA_LOG_MODID_OFFSET) | 11)
+#endif
diff --git a/drivers/scsi/bfa/include/log/bfa_log_wdrv.h b/drivers/scsi/bfa/include/log/bfa_log_wdrv.h
new file mode 100644
index 000000000000..809a95f7afe2
--- /dev/null
+++ b/drivers/scsi/bfa/include/log/bfa_log_wdrv.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/*
+ * messages define for WDRV Module
+ */
+#ifndef __BFA_LOG_WDRV_H__
+#define __BFA_LOG_WDRV_H__
+#include <cs/bfa_log.h>
+#define BFA_LOG_WDRV_IOC_INIT_ERROR \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 1)
+#define BFA_LOG_WDRV_IOC_INTERNAL_ERROR \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 2)
+#define BFA_LOG_WDRV_IOC_START_ERROR \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 3)
+#define BFA_LOG_WDRV_IOC_STOP_ERROR \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 4)
+#define BFA_LOG_WDRV_INSUFFICIENT_RESOURCES \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 5)
+#define BFA_LOG_WDRV_BASE_ADDRESS_MAP_ERROR \
+ (((u32) BFA_LOG_WDRV_ID << BFA_LOG_MODID_OFFSET) | 6)
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/ct.h b/drivers/scsi/bfa/include/protocol/ct.h
new file mode 100644
index 000000000000..c8648bcba41a
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/ct.h
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __CT_H__
+#define __CT_H__
+
+#include <protocol/types.h>
+
+#pragma pack(1)
+
+struct ct_hdr_s{
+ u32 rev_id:8; /* Revision of the CT */
+ u32 in_id:24; /* Initiator Id */
+ u32 gs_type:8; /* Generic service Type */
+ u32 gs_sub_type:8; /* Generic service sub type */
+ u32 options:8; /* options */
+ u32 rsvrd:8; /* reserved */
+ u32 cmd_rsp_code:16;/* ct command/response code */
+ u32 max_res_size:16;/* maximum/residual size */
+ u32 frag_id:8; /* fragment ID */
+ u32 reason_code:8; /* reason code */
+ u32 exp_code:8; /* explanation code */
+ u32 vendor_unq:8; /* vendor unique */
+};
+
+/*
+ * defines for the Revision
+ */
+enum {
+ CT_GS3_REVISION = 0x01,
+};
+
+/*
+ * defines for gs_type
+ */
+enum {
+ CT_GSTYPE_KEYSERVICE = 0xF7,
+ CT_GSTYPE_ALIASSERVICE = 0xF8,
+ CT_GSTYPE_MGMTSERVICE = 0xFA,
+ CT_GSTYPE_TIMESERVICE = 0xFB,
+ CT_GSTYPE_DIRSERVICE = 0xFC,
+};
+
+/*
+ * defines for gs_sub_type for gs type directory service
+ */
+enum {
+ CT_GSSUBTYPE_NAMESERVER = 0x02,
+};
+
+/*
+ * defines for gs_sub_type for gs type management service
+ */
+enum {
+ CT_GSSUBTYPE_CFGSERVER = 0x01,
+ CT_GSSUBTYPE_UNZONED_NS = 0x02,
+ CT_GSSUBTYPE_ZONESERVER = 0x03,
+ CT_GSSUBTYPE_LOCKSERVER = 0x04,
+ CT_GSSUBTYPE_HBA_MGMTSERVER = 0x10, /* for FDMI */
+};
+
+/*
+ * defines for CT response code field
+ */
+enum {
+ CT_RSP_REJECT = 0x8001,
+ CT_RSP_ACCEPT = 0x8002,
+};
+
+/*
+ * defintions for CT reason code
+ */
+enum {
+ CT_RSN_INV_CMD = 0x01,
+ CT_RSN_INV_VER = 0x02,
+ CT_RSN_LOGIC_ERR = 0x03,
+ CT_RSN_INV_SIZE = 0x04,
+ CT_RSN_LOGICAL_BUSY = 0x05,
+ CT_RSN_PROTO_ERR = 0x07,
+ CT_RSN_UNABLE_TO_PERF = 0x09,
+ CT_RSN_NOT_SUPP = 0x0B,
+ CT_RSN_SERVER_NOT_AVBL = 0x0D,
+ CT_RSN_SESSION_COULD_NOT_BE_ESTBD = 0x0E,
+ CT_RSN_VENDOR_SPECIFIC = 0xFF,
+
+};
+
+/*
+ * definitions for explanations code for Name server
+ */
+enum {
+ CT_NS_EXP_NOADDITIONAL = 0x00,
+ CT_NS_EXP_ID_NOT_REG = 0x01,
+ CT_NS_EXP_PN_NOT_REG = 0x02,
+ CT_NS_EXP_NN_NOT_REG = 0x03,
+ CT_NS_EXP_CS_NOT_REG = 0x04,
+ CT_NS_EXP_IPN_NOT_REG = 0x05,
+ CT_NS_EXP_IPA_NOT_REG = 0x06,
+ CT_NS_EXP_FT_NOT_REG = 0x07,
+ CT_NS_EXP_SPN_NOT_REG = 0x08,
+ CT_NS_EXP_SNN_NOT_REG = 0x09,
+ CT_NS_EXP_PT_NOT_REG = 0x0A,
+ CT_NS_EXP_IPP_NOT_REG = 0x0B,
+ CT_NS_EXP_FPN_NOT_REG = 0x0C,
+ CT_NS_EXP_HA_NOT_REG = 0x0D,
+ CT_NS_EXP_FD_NOT_REG = 0x0E,
+ CT_NS_EXP_FF_NOT_REG = 0x0F,
+ CT_NS_EXP_ACCESSDENIED = 0x10,
+ CT_NS_EXP_UNACCEPTABLE_ID = 0x11,
+ CT_NS_EXP_DATABASEEMPTY = 0x12,
+ CT_NS_EXP_NOT_REG_IN_SCOPE = 0x13,
+ CT_NS_EXP_DOM_ID_NOT_PRESENT = 0x14,
+ CT_NS_EXP_PORT_NUM_NOT_PRESENT = 0x15,
+ CT_NS_EXP_NO_DEVICE_ATTACHED = 0x16
+};
+
+/*
+ * defintions for the explanation code for all servers
+ */
+enum {
+ CT_EXP_AUTH_EXCEPTION = 0xF1,
+ CT_EXP_DB_FULL = 0xF2,
+ CT_EXP_DB_EMPTY = 0xF3,
+ CT_EXP_PROCESSING_REQ = 0xF4,
+ CT_EXP_UNABLE_TO_VERIFY_CONN = 0xF5,
+ CT_EXP_DEVICES_NOT_IN_CMN_ZONE = 0xF6
+};
+
+/*
+ * Command codes for Name server
+ */
+enum {
+ GS_GID_PN = 0x0121, /* Get Id on port name */
+ GS_GPN_ID = 0x0112, /* Get port name on ID */
+ GS_GNN_ID = 0x0113, /* Get node name on ID */
+ GS_GID_FT = 0x0171, /* Get Id on FC4 type */
+ GS_GSPN_ID = 0x0118, /* Get symbolic PN on ID */
+ GS_RFT_ID = 0x0217, /* Register fc4type on ID */
+ GS_RSPN_ID = 0x0218, /* Register symbolic PN on ID */
+ GS_RPN_ID = 0x0212, /* Register port name */
+ GS_RNN_ID = 0x0213, /* Register node name */
+ GS_RCS_ID = 0x0214, /* Register class of service */
+ GS_RPT_ID = 0x021A, /* Register port type */
+ GS_GA_NXT = 0x0100, /* Get all next */
+ GS_RFF_ID = 0x021F, /* Register FC4 Feature */
+};
+
+struct fcgs_id_req_s{
+ u32 rsvd:8;
+ u32 dap:24; /* port identifier */
+};
+#define fcgs_gpnid_req_t struct fcgs_id_req_s
+#define fcgs_gnnid_req_t struct fcgs_id_req_s
+#define fcgs_gspnid_req_t struct fcgs_id_req_s
+
+struct fcgs_gidpn_req_s{
+ wwn_t port_name; /* port wwn */
+};
+
+struct fcgs_gidpn_resp_s{
+ u32 rsvd:8;
+ u32 dap:24; /* port identifier */
+};
+
+/**
+ * RFT_ID
+ */
+struct fcgs_rftid_req_s {
+ u32 rsvd:8;
+ u32 dap:24; /* port identifier */
+ u32 fc4_type[8]; /* fc4 types */
+};
+
+/**
+ * RFF_ID : Register FC4 features.
+ */
+
+#define FC_GS_FCP_FC4_FEATURE_INITIATOR 0x02
+#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 */
+};
+
+/**
+ * GID_FT Request
+ */
+struct fcgs_gidft_req_s{
+ u8 reserved;
+ u8 domain_id; /* domain, 0 - all fabric */
+ u8 area_id; /* area, 0 - whole domain */
+ u8 fc4_type; /* FC_TYPE_FCP for SCSI devices */
+}; /* GID_FT Request */
+
+/**
+ * GID_FT Response
+ */
+struct fcgs_gidft_resp_s {
+ u8 last:1; /* last port identifier flag */
+ u8 reserved:7;
+ u32 pid:24; /* port identifier */
+}; /* GID_FT Response */
+
+/**
+ * RSPN_ID
+ */
+struct fcgs_rspnid_req_s{
+ u32 rsvd:8;
+ u32 dap:24; /* port identifier */
+ u8 spn_len; /* symbolic port name length */
+ u8 spn[256]; /* symbolic port name */
+};
+
+/**
+ * RPN_ID
+ */
+struct fcgs_rpnid_req_s{
+ u32 rsvd:8;
+ u32 port_id:24;
+ wwn_t port_name;
+};
+
+/**
+ * RNN_ID
+ */
+struct fcgs_rnnid_req_s{
+ u32 rsvd:8;
+ u32 port_id:24;
+ wwn_t node_name;
+};
+
+/**
+ * RCS_ID
+ */
+struct fcgs_rcsid_req_s{
+ u32 rsvd:8;
+ u32 port_id:24;
+ u32 cos;
+};
+
+/**
+ * RPT_ID
+ */
+struct fcgs_rptid_req_s{
+ u32 rsvd:8;
+ u32 port_id:24;
+ u32 port_type:8;
+ u32 rsvd1:24;
+};
+
+/**
+ * GA_NXT Request
+ */
+struct fcgs_ganxt_req_s{
+ u32 rsvd:8;
+ u32 port_id:24;
+};
+
+/**
+ * GA_NXT Response
+ */
+struct fcgs_ganxt_rsp_s{
+ u32 port_type:8; /* Port Type */
+ u32 port_id:24; /* Port Identifier */
+ wwn_t port_name; /* Port Name */
+ u8 spn_len; /* Length of Symbolic Port Name */
+ char spn[255]; /* Symbolic Port Name */
+ wwn_t node_name; /* Node Name */
+ u8 snn_len; /* Length of Symbolic Node Name */
+ char snn[255]; /* Symbolic Node Name */
+ u8 ipa[8]; /* Initial Process Associator */
+ u8 ip[16]; /* IP Address */
+ u32 cos; /* Class of Service */
+ u32 fc4types[8]; /* FC-4 TYPEs */
+ wwn_t fabric_port_name;
+ /* Fabric Port Name */
+ u32 rsvd:8; /* Reserved */
+ u32 hard_addr:24; /* Hard Address */
+};
+
+/*
+ * Fabric Config Server
+ */
+
+/*
+ * Command codes for Fabric Configuration Server
+ */
+enum {
+ GS_FC_GFN_CMD = 0x0114, /* GS FC Get Fabric Name */
+ GS_FC_GMAL_CMD = 0x0116, /* GS FC GMAL */
+ GS_FC_TRACE_CMD = 0x0400, /* GS FC Trace Route */
+ GS_FC_PING_CMD = 0x0401, /* GS FC Ping */
+};
+
+/*
+ * Source or Destination Port Tags.
+ */
+enum {
+ GS_FTRACE_TAG_NPORT_ID = 1,
+ GS_FTRACE_TAG_NPORT_NAME = 2,
+};
+
+/*
+* Port Value : Could be a Port id or wwn
+ */
+union fcgs_port_val_u{
+ u32 nport_id;
+ wwn_t nport_wwn;
+};
+
+#define GS_FTRACE_MAX_HOP_COUNT 20
+#define GS_FTRACE_REVISION 1
+
+/*
+ * Ftrace Related Structures.
+ */
+
+/*
+ * STR (Switch Trace) Reject Reason Codes. From FC-SW.
+ */
+enum {
+ GS_FTRACE_STR_CMD_COMPLETED_SUCC = 0,
+ GS_FTRACE_STR_CMD_NOT_SUPP_IN_NEXT_SWITCH,
+ GS_FTRACE_STR_NO_RESP_FROM_NEXT_SWITCH,
+ GS_FTRACE_STR_MAX_HOP_CNT_REACHED,
+ GS_FTRACE_STR_SRC_PORT_NOT_FOUND,
+ GS_FTRACE_STR_DST_PORT_NOT_FOUND,
+ GS_FTRACE_STR_DEVICES_NOT_IN_COMMON_ZONE,
+ GS_FTRACE_STR_NO_ROUTE_BW_PORTS,
+ GS_FTRACE_STR_NO_ADDL_EXPLN,
+ GS_FTRACE_STR_FABRIC_BUSY,
+ GS_FTRACE_STR_FABRIC_BUILD_IN_PROGRESS,
+ GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_START = 0xf0,
+ GS_FTRACE_STR_VENDOR_SPECIFIC_ERR_END = 0xff,
+};
+
+/*
+ * Ftrace Request
+ */
+struct fcgs_ftrace_req_s{
+ u32 revision;
+ u16 src_port_tag; /* Source Port tag */
+ u16 src_port_len; /* Source Port len */
+ union fcgs_port_val_u src_port_val; /* Source Port value */
+ u16 dst_port_tag; /* Destination Port tag */
+ u16 dst_port_len; /* Destination Port len */
+ union fcgs_port_val_u dst_port_val; /* Destination Port value */
+ u32 token;
+ u8 vendor_id[8]; /* T10 Vendor Identifier */
+ u8 vendor_info[8]; /* Vendor specific Info */
+ u32 max_hop_cnt; /* Max Hop Count */
+};
+
+/*
+ * Path info structure
+ */
+struct fcgs_ftrace_path_info_s{
+ wwn_t switch_name; /* Switch WWN */
+ u32 domain_id;
+ wwn_t ingress_port_name; /* Ingress ports wwn */
+ u32 ingress_phys_port_num; /* Ingress ports physical port
+ * number
+ */
+ wwn_t egress_port_name; /* Ingress ports wwn */
+ u32 egress_phys_port_num; /* Ingress ports physical port
+ * number
+ */
+};
+
+/*
+ * Ftrace Acc Response
+ */
+struct fcgs_ftrace_resp_s{
+ u32 revision;
+ u32 token;
+ u8 vendor_id[8]; /* T10 Vendor Identifier */
+ u8 vendor_info[8]; /* Vendor specific Info */
+ u32 str_rej_reason_code; /* STR Reject Reason Code */
+ u32 num_path_info_entries; /* No. of path info entries */
+ /*
+ * path info entry/entries.
+ */
+ struct fcgs_ftrace_path_info_s path_info[1];
+
+};
+
+/*
+* Fabric Config Server : FCPing
+ */
+
+/*
+ * FC Ping Request
+ */
+struct fcgs_fcping_req_s{
+ u32 revision;
+ u16 port_tag;
+ u16 port_len; /* Port len */
+ union fcgs_port_val_u port_val; /* Port value */
+ u32 token;
+};
+
+/*
+ * FC Ping Response
+ */
+struct fcgs_fcping_resp_s{
+ u32 token;
+};
+
+/*
+ * Command codes for zone server query.
+ */
+enum {
+ ZS_GZME = 0x0124, /* Get zone member extended */
+};
+
+/*
+ * ZS GZME request
+ */
+#define ZS_GZME_ZNAMELEN 32
+struct zs_gzme_req_s{
+ u8 znamelen;
+ u8 rsvd[3];
+ u8 zname[ZS_GZME_ZNAMELEN];
+};
+
+enum zs_mbr_type{
+ ZS_MBR_TYPE_PWWN = 1,
+ ZS_MBR_TYPE_DOMPORT = 2,
+ ZS_MBR_TYPE_PORTID = 3,
+ ZS_MBR_TYPE_NWWN = 4,
+};
+
+struct zs_mbr_wwn_s{
+ u8 mbr_type;
+ u8 rsvd[3];
+ wwn_t wwn;
+};
+
+struct zs_query_resp_s{
+ u32 nmbrs; /* number of zone members */
+ struct zs_mbr_wwn_s mbr[1];
+};
+
+/*
+ * GMAL Command ( Get ( interconnect Element) Management Address List)
+ * To retrieve the IP Address of a Switch.
+ */
+
+#define CT_GMAL_RESP_PREFIX_TELNET "telnet://"
+#define CT_GMAL_RESP_PREFIX_HTTP "http://"
+
+/* GMAL/GFN request */
+struct fcgs_req_s {
+ wwn_t wwn; /* PWWN/NWWN */
+};
+
+#define fcgs_gmal_req_t struct fcgs_req_s
+#define fcgs_gfn_req_t struct fcgs_req_s
+
+/* Accept Response to GMAL */
+struct fcgs_gmal_resp_s {
+ u32 ms_len; /* Num of entries */
+ u8 ms_ma[256];
+};
+
+struct fc_gmal_entry_s {
+ u8 len;
+ u8 prefix[7]; /* like "http://" */
+ u8 ip_addr[248];
+};
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/fc.h b/drivers/scsi/bfa/include/protocol/fc.h
new file mode 100644
index 000000000000..14969eecf6a9
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/fc.h
@@ -0,0 +1,1105 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __FC_H__
+#define __FC_H__
+
+#include <protocol/types.h>
+
+#pragma pack(1)
+
+/*
+ * Fibre Channel Header Structure (FCHS) definition
+ */
+struct fchs_s {
+#ifdef __BIGENDIAN
+ u32 routing:4; /* routing bits */
+ u32 cat_info:4; /* category info */
+#else
+ u32 cat_info:4; /* category info */
+ u32 routing:4; /* routing bits */
+#endif
+ u32 d_id:24; /* destination identifier */
+
+ u32 cs_ctl:8; /* class specific control */
+ u32 s_id:24; /* source identifier */
+
+ u32 type:8; /* data structure type */
+ u32 f_ctl:24; /* initial frame control */
+
+ u8 seq_id; /* sequence identifier */
+ u8 df_ctl; /* data field control */
+ u16 seq_cnt; /* sequence count */
+
+ u16 ox_id; /* originator exchange ID */
+ u16 rx_id; /* responder exchange ID */
+
+ u32 ro; /* relative offset */
+};
+/*
+ * Fibre Channel BB_E Header Structure
+ */
+struct fcbbehs_s {
+ u16 ver_rsvd;
+ u32 rsvd[2];
+ u32 rsvd__sof;
+};
+
+#define FC_SEQ_ID_MAX 256
+
+/*
+ * routing bit definitions
+ */
+enum {
+ FC_RTG_FC4_DEV_DATA = 0x0, /* FC-4 Device Data */
+ FC_RTG_EXT_LINK = 0x2, /* Extended Link Data */
+ FC_RTG_FC4_LINK_DATA = 0x3, /* FC-4 Link Data */
+ FC_RTG_VIDEO_DATA = 0x4, /* Video Data */
+ FC_RTG_EXT_HDR = 0x5, /* VFT, IFR or Encapsuled */
+ FC_RTG_BASIC_LINK = 0x8, /* Basic Link data */
+ FC_RTG_LINK_CTRL = 0xC, /* Link Control */
+};
+
+/*
+ * information category for extended link data and FC-4 Link Data
+ */
+enum {
+ FC_CAT_LD_REQUEST = 0x2, /* Request */
+ FC_CAT_LD_REPLY = 0x3, /* Reply */
+ FC_CAT_LD_DIAG = 0xF, /* for DIAG use only */
+};
+
+/*
+ * information category for extended headers (VFT, IFR or encapsulation)
+ */
+enum {
+ FC_CAT_VFT_HDR = 0x0, /* Virtual fabric tagging header */
+ FC_CAT_IFR_HDR = 0x1, /* Inter-Fabric routing header */
+ FC_CAT_ENC_HDR = 0x2, /* Encapsulation header */
+};
+
+/*
+ * information category for FC-4 device data
+ */
+enum {
+ FC_CAT_UNCATEG_INFO = 0x0, /* Uncategorized information */
+ FC_CAT_SOLICIT_DATA = 0x1, /* Solicited Data */
+ FC_CAT_UNSOLICIT_CTRL = 0x2, /* Unsolicited Control */
+ FC_CAT_SOLICIT_CTRL = 0x3, /* Solicited Control */
+ FC_CAT_UNSOLICIT_DATA = 0x4, /* Unsolicited Data */
+ FC_CAT_DATA_DESC = 0x5, /* Data Descriptor */
+ FC_CAT_UNSOLICIT_CMD = 0x6, /* Unsolicited Command */
+ FC_CAT_CMD_STATUS = 0x7, /* Command Status */
+};
+
+/*
+ * information category for Link Control
+ */
+enum {
+ FC_CAT_ACK_1 = 0x00,
+ FC_CAT_ACK_0_N = 0x01,
+ FC_CAT_P_RJT = 0x02,
+ FC_CAT_F_RJT = 0x03,
+ FC_CAT_P_BSY = 0x04,
+ FC_CAT_F_BSY_DATA = 0x05,
+ FC_CAT_F_BSY_LINK_CTL = 0x06,
+ FC_CAT_F_LCR = 0x07,
+ FC_CAT_NTY = 0x08,
+ FC_CAT_END = 0x09,
+};
+
+/*
+ * Type Field Definitions. FC-PH Section 18.5 pg. 165
+ */
+enum {
+ FC_TYPE_BLS = 0x0, /* Basic Link Service */
+ FC_TYPE_ELS = 0x1, /* Extended Link Service */
+ FC_TYPE_IP = 0x5, /* IP */
+ FC_TYPE_FCP = 0x8, /* SCSI-FCP */
+ FC_TYPE_GPP = 0x9, /* SCSI_GPP */
+ FC_TYPE_SERVICES = 0x20, /* Fibre Channel Services */
+ FC_TYPE_FC_FSS = 0x22, /* Fabric Switch Services */
+ FC_TYPE_FC_AL = 0x23, /* FC-AL */
+ FC_TYPE_FC_SNMP = 0x24, /* FC-SNMP */
+ FC_TYPE_MAX = 256, /* 256 FC-4 types */
+};
+
+struct fc_fc4types_s{
+ u8 bits[FC_TYPE_MAX / 8];
+};
+
+/*
+ * Frame Control Definitions. FC-PH Table-45. pg. 168
+ */
+enum {
+ FCTL_EC_ORIG = 0x000000, /* exchange originator */
+ FCTL_EC_RESP = 0x800000, /* exchange responder */
+ FCTL_SEQ_INI = 0x000000, /* sequence initiator */
+ FCTL_SEQ_REC = 0x400000, /* sequence recipient */
+ FCTL_FS_EXCH = 0x200000, /* first sequence of xchg */
+ FCTL_LS_EXCH = 0x100000, /* last sequence of xchg */
+ FCTL_END_SEQ = 0x080000, /* last frame of sequence */
+ FCTL_SI_XFER = 0x010000, /* seq initiative transfer */
+ FCTL_RO_PRESENT = 0x000008, /* relative offset present */
+ FCTL_FILLBYTE_MASK = 0x000003 /* , fill byte mask */
+};
+
+/*
+ * Fabric Well Known Addresses
+ */
+enum {
+ FC_MIN_WELL_KNOWN_ADDR = 0xFFFFF0,
+ FC_DOMAIN_CONTROLLER_MASK = 0xFFFC00,
+ FC_ALIAS_SERVER = 0xFFFFF8,
+ FC_MGMT_SERVER = 0xFFFFFA,
+ FC_TIME_SERVER = 0xFFFFFB,
+ FC_NAME_SERVER = 0xFFFFFC,
+ FC_FABRIC_CONTROLLER = 0xFFFFFD,
+ FC_FABRIC_PORT = 0xFFFFFE,
+ FC_BROADCAST_SERVER = 0xFFFFFF
+};
+
+/*
+ * domain/area/port defines
+ */
+#define FC_DOMAIN_MASK 0xFF0000
+#define FC_DOMAIN_SHIFT 16
+#define FC_AREA_MASK 0x00FF00
+#define FC_AREA_SHIFT 8
+#define FC_PORT_MASK 0x0000FF
+#define FC_PORT_SHIFT 0
+
+#define FC_GET_DOMAIN(p) (((p) & FC_DOMAIN_MASK) >> FC_DOMAIN_SHIFT)
+#define FC_GET_AREA(p) (((p) & FC_AREA_MASK) >> FC_AREA_SHIFT)
+#define FC_GET_PORT(p) (((p) & FC_PORT_MASK) >> FC_PORT_SHIFT)
+
+#define FC_DOMAIN_CTRLR(p) (FC_DOMAIN_CONTROLLER_MASK | (FC_GET_DOMAIN(p)))
+
+enum {
+ FC_RXID_ANY = 0xFFFFU,
+};
+
+/*
+ * generic ELS command
+ */
+struct fc_els_cmd_s{
+ u32 els_code:8; /* ELS Command Code */
+ u32 reserved:24;
+};
+
+/*
+ * ELS Command Codes. FC-PH Table-75. pg. 223
+ */
+enum {
+ FC_ELS_LS_RJT = 0x1, /* Link Service Reject. */
+ FC_ELS_ACC = 0x02, /* Accept */
+ FC_ELS_PLOGI = 0x03, /* N_Port Login. */
+ FC_ELS_FLOGI = 0x04, /* F_Port Login. */
+ FC_ELS_LOGO = 0x05, /* Logout. */
+ FC_ELS_ABTX = 0x06, /* Abort Exchange */
+ FC_ELS_RES = 0x08, /* Read Exchange status */
+ FC_ELS_RSS = 0x09, /* Read sequence status block */
+ FC_ELS_RSI = 0x0A, /* Request Sequence Initiative */
+ FC_ELS_ESTC = 0x0C, /* Estimate Credit. */
+ FC_ELS_RTV = 0x0E, /* Read Timeout Value. */
+ FC_ELS_RLS = 0x0F, /* Read Link Status. */
+ FC_ELS_ECHO = 0x10, /* Echo */
+ FC_ELS_TEST = 0x11, /* Test */
+ FC_ELS_RRQ = 0x12, /* Reinstate Recovery Qualifier. */
+ FC_ELS_REC = 0x13, /* Add this for TAPE support in FCR */
+ FC_ELS_PRLI = 0x20, /* Process Login */
+ FC_ELS_PRLO = 0x21, /* Process Logout. */
+ FC_ELS_SCN = 0x22, /* State Change Notification. */
+ FC_ELS_TPRLO = 0x24, /* Third Party Process Logout. */
+ FC_ELS_PDISC = 0x50, /* Discover N_Port Parameters. */
+ FC_ELS_FDISC = 0x51, /* Discover F_Port Parameters. */
+ FC_ELS_ADISC = 0x52, /* Discover Address. */
+ FC_ELS_FAN = 0x60, /* Fabric Address Notification */
+ FC_ELS_RSCN = 0x61, /* Reg State Change Notification */
+ FC_ELS_SCR = 0x62, /* State Change Registration. */
+ FC_ELS_RTIN = 0x77, /* Mangement server request */
+ FC_ELS_RNID = 0x78, /* Mangement server request */
+ FC_ELS_RLIR = 0x79, /* Registered Link Incident Record */
+
+ FC_ELS_RPSC = 0x7D, /* Report Port Speed Capabilities */
+ FC_ELS_QSA = 0x7E, /* Query Security Attributes. Ref FC-SP */
+ FC_ELS_E2E_LBEACON = 0x81,
+ /* End-to-End Link Beacon */
+ FC_ELS_AUTH = 0x90, /* Authentication. Ref FC-SP */
+ FC_ELS_RFCN = 0x97, /* Request Fabric Change Notification. Ref
+ *FC-SP */
+
+};
+
+/*
+ * Version numbers for FC-PH standards,
+ * used in login to indicate what port
+ * supports. See FC-PH-X table 158.
+ */
+enum {
+ FC_PH_VER_4_3 = 0x09,
+ FC_PH_VER_PH_3 = 0x20,
+};
+
+/*
+ * PDU size defines
+ */
+enum {
+ FC_MIN_PDUSZ = 512,
+ FC_MAX_PDUSZ = 2112,
+};
+
+/*
+ * N_Port PLOGI Common Service Parameters.
+ * FC-PH-x. Figure-76. pg. 308.
+ */
+struct fc_plogi_csp_s{
+ u8 verhi; /* FC-PH high version */
+ u8 verlo; /* FC-PH low version */
+ u16 bbcred; /* BB_Credit */
+
+#ifdef __BIGENDIAN
+ u8 ciro:1, /* continuously increasing RO */
+ rro:1, /* random relative offset */
+ npiv_supp:1, /* NPIV supported */
+ port_type:1, /* N_Port/F_port */
+ altbbcred:1, /* alternate BB_Credit */
+ resolution:1, /* ms/ns ED_TOV resolution */
+ vvl_info:1, /* VVL Info included */
+ reserved1:1;
+
+ u8 hg_supp:1,
+ query_dbc:1,
+ security:1,
+ sync_cap:1,
+ r_t_tov:1,
+ dh_dup_supp:1,
+ cisc:1, /* continuously increasing seq count */
+ payload:1;
+#else
+ u8 reserved2:2,
+ resolution:1, /* ms/ns ED_TOV resolution */
+ altbbcred:1, /* alternate BB_Credit */
+ port_type:1, /* N_Port/F_port */
+ npiv_supp:1, /* NPIV supported */
+ rro:1, /* random relative offset */
+ ciro:1; /* continuously increasing RO */
+
+ u8 payload:1,
+ cisc:1, /* continuously increasing seq count */
+ dh_dup_supp:1,
+ r_t_tov:1,
+ sync_cap:1,
+ security:1,
+ query_dbc:1,
+ hg_supp:1;
+#endif
+
+ u16 rxsz; /* recieve data_field size */
+
+ u16 conseq;
+ u16 ro_bitmap;
+
+ u32 e_d_tov;
+};
+
+/*
+ * N_Port PLOGI Class Specific Parameters.
+ * FC-PH-x. Figure 78. pg. 318.
+ */
+struct fc_plogi_clp_s{
+#ifdef __BIGENDIAN
+ u32 class_valid:1;
+ u32 intermix:1; /* class intermix supported if set =1.
+ * valid only for class1. Reserved for
+ * class2 & class3
+ */
+ u32 reserved1:2;
+ u32 sequential:1;
+ u32 reserved2:3;
+#else
+ u32 reserved2:3;
+ u32 sequential:1;
+ u32 reserved1:2;
+ u32 intermix:1; /* class intermix supported if set =1.
+ * valid only for class1. Reserved for
+ * class2 & class3
+ */
+ u32 class_valid:1;
+#endif
+
+ u32 reserved3:24;
+
+ u32 reserved4:16;
+ u32 rxsz:16; /* Receive data_field size */
+
+ u32 reserved5:8;
+ u32 conseq:8;
+ u32 e2e_credit:16; /* end to end credit */
+
+ u32 reserved7:8;
+ u32 ospx:8;
+ u32 reserved8:16;
+};
+
+#define FLOGI_VVL_BRCD 0x42524344 /* ASCII value for each character in
+ * string "BRCD" */
+
+/*
+ * PLOGI els command and reply payload
+ */
+struct fc_logi_s{
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ struct fc_plogi_csp_s csp; /* common service params */
+ wwn_t port_name;
+ wwn_t node_name;
+ struct fc_plogi_clp_s class1; /* class 1 service parameters */
+ struct fc_plogi_clp_s class2; /* class 2 service parameters */
+ struct fc_plogi_clp_s class3; /* class 3 service parameters */
+ struct fc_plogi_clp_s class4; /* class 4 service parameters */
+ u8 vvl[16]; /* vendor version level */
+};
+
+/*
+ * LOGO els command payload
+ */
+struct fc_logo_s{
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 nport_id:24; /* N_Port identifier of source */
+ wwn_t orig_port_name; /* Port name of the LOGO originator */
+};
+
+/*
+ * ADISC els command payload
+ */
+struct fc_adisc_s {
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 orig_HA:24; /* originator hard address */
+ wwn_t orig_port_name; /* originator port name */
+ wwn_t orig_node_name; /* originator node name */
+ u32 res2:8;
+ u32 nport_id:24; /* originator NPortID */
+};
+
+/*
+ * Exchange status block
+ */
+struct fc_exch_status_blk_s{
+ u32 oxid:16;
+ u32 rxid:16;
+ u32 res1:8;
+ u32 orig_np:24; /* originator NPortID */
+ u32 res2:8;
+ u32 resp_np:24; /* responder NPortID */
+ u32 es_bits;
+ u32 res3;
+ /*
+ * un modified section of the fields
+ */
+};
+
+/*
+ * RES els command payload
+ */
+struct fc_res_s {
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 nport_id:24; /* N_Port identifier of source */
+ u32 oxid:16;
+ u32 rxid:16;
+ u8 assoc_hdr[32];
+};
+
+/*
+ * RES els accept payload
+ */
+struct fc_res_acc_s{
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ struct fc_exch_status_blk_s fc_exch_blk; /* Exchange status block */
+};
+
+/*
+ * REC els command payload
+ */
+struct fc_rec_s {
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 nport_id:24; /* N_Port identifier of source */
+ u32 oxid:16;
+ u32 rxid:16;
+};
+
+#define FC_REC_ESB_OWN_RSP 0x80000000 /* responder owns */
+#define FC_REC_ESB_SI 0x40000000 /* SI is owned */
+#define FC_REC_ESB_COMP 0x20000000 /* exchange is complete */
+#define FC_REC_ESB_ENDCOND_ABN 0x10000000 /* abnormal ending */
+#define FC_REC_ESB_RQACT 0x04000000 /* recovery qual active */
+#define FC_REC_ESB_ERRP_MSK 0x03000000
+#define FC_REC_ESB_OXID_INV 0x00800000 /* invalid OXID */
+#define FC_REC_ESB_RXID_INV 0x00400000 /* invalid RXID */
+#define FC_REC_ESB_PRIO_INUSE 0x00200000
+
+/*
+ * REC els accept payload
+ */
+struct fc_rec_acc_s {
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 oxid:16;
+ u32 rxid:16;
+ u32 res1:8;
+ u32 orig_id:24; /* N_Port id of exchange originator */
+ u32 res2:8;
+ u32 resp_id:24; /* N_Port id of exchange responder */
+ u32 count; /* data transfer count */
+ u32 e_stat; /* exchange status */
+};
+
+/*
+ * RSI els payload
+ */
+struct fc_rsi_s {
+ struct fc_els_cmd_s els_cmd;
+ u32 res1:8;
+ u32 orig_sid:24;
+ u32 oxid:16;
+ u32 rxid:16;
+};
+
+/*
+ * structure for PRLI paramater pages, both request & response
+ * see FC-PH-X table 113 & 115 for explanation also FCP table 8
+ */
+struct fc_prli_params_s{
+ u32 reserved:16;
+#ifdef __BIGENDIAN
+ u32 reserved1:5;
+ u32 rec_support:1;
+ u32 task_retry_id:1;
+ u32 retry:1;
+
+ u32 confirm:1;
+ u32 doverlay:1;
+ u32 initiator:1;
+ u32 target:1;
+ u32 cdmix:1;
+ u32 drmix:1;
+ u32 rxrdisab:1;
+ u32 wxrdisab:1;
+#else
+ u32 retry:1;
+ u32 task_retry_id:1;
+ u32 rec_support:1;
+ u32 reserved1:5;
+
+ u32 wxrdisab:1;
+ u32 rxrdisab:1;
+ u32 drmix:1;
+ u32 cdmix:1;
+ u32 target:1;
+ u32 initiator:1;
+ u32 doverlay:1;
+ u32 confirm:1;
+#endif
+};
+
+/*
+ * valid values for rspcode in PRLI ACC payload
+ */
+enum {
+ FC_PRLI_ACC_XQTD = 0x1, /* request executed */
+ FC_PRLI_ACC_PREDEF_IMG = 0x5, /* predefined image - no prli needed */
+};
+
+struct fc_prli_params_page_s{
+ u32 type:8;
+ u32 codext:8;
+#ifdef __BIGENDIAN
+ u32 origprocasv:1;
+ u32 rsppav:1;
+ u32 imagepair:1;
+ u32 reserved1:1;
+ u32 rspcode:4;
+#else
+ u32 rspcode:4;
+ u32 reserved1:1;
+ u32 imagepair:1;
+ u32 rsppav:1;
+ u32 origprocasv:1;
+#endif
+ u32 reserved2:8;
+
+ u32 origprocas;
+ u32 rspprocas;
+ struct fc_prli_params_s servparams;
+};
+
+/*
+ * PRLI request and accept payload, FC-PH-X tables 112 & 114
+ */
+struct fc_prli_s{
+ u32 command:8;
+ u32 pglen:8;
+ u32 pagebytes:16;
+ struct fc_prli_params_page_s parampage;
+};
+
+/*
+ * PRLO logout params page
+ */
+struct fc_prlo_params_page_s{
+ u32 type:8;
+ u32 type_ext:8;
+#ifdef __BIGENDIAN
+ u32 opa_valid:1; /* originator process associator
+ * valid
+ */
+ u32 rpa_valid:1; /* responder process associator valid */
+ u32 res1:14;
+#else
+ u32 res1:14;
+ u32 rpa_valid:1; /* responder process associator valid */
+ u32 opa_valid:1; /* originator process associator
+ * valid
+ */
+#endif
+ u32 orig_process_assc;
+ u32 resp_process_assc;
+
+ u32 res2;
+};
+
+/*
+ * PRLO els command payload
+ */
+struct fc_prlo_s{
+ u32 command:8;
+ u32 page_len:8;
+ u32 payload_len:16;
+ struct fc_prlo_params_page_s prlo_params[1];
+};
+
+/*
+ * PRLO Logout response parameter page
+ */
+struct fc_prlo_acc_params_page_s{
+ u32 type:8;
+ u32 type_ext:8;
+
+#ifdef __BIGENDIAN
+ u32 opa_valid:1; /* originator process associator
+ * valid
+ */
+ u32 rpa_valid:1; /* responder process associator valid */
+ u32 res1:14;
+#else
+ u32 res1:14;
+ u32 rpa_valid:1; /* responder process associator valid */
+ u32 opa_valid:1; /* originator process associator
+ * valid
+ */
+#endif
+ u32 orig_process_assc;
+ u32 resp_process_assc;
+
+ u32 fc4type_csp;
+};
+
+/*
+ * PRLO els command ACC payload
+ */
+struct fc_prlo_acc_s{
+ u32 command:8;
+ u32 page_len:8;
+ u32 payload_len:16;
+ struct fc_prlo_acc_params_page_s prlo_acc_params[1];
+};
+
+/*
+ * SCR els command payload
+ */
+enum {
+ FC_SCR_REG_FUNC_FABRIC_DETECTED = 0x01,
+ FC_SCR_REG_FUNC_N_PORT_DETECTED = 0x02,
+ FC_SCR_REG_FUNC_FULL = 0x03,
+ FC_SCR_REG_FUNC_CLEAR_REG = 0xFF,
+};
+
+/* SCR VU registrations */
+enum {
+ FC_VU_SCR_REG_FUNC_FABRIC_NAME_CHANGE = 0x01
+};
+
+struct fc_scr_s{
+ u32 command:8;
+ u32 res:24;
+ u32 vu_reg_func:8; /* Vendor Unique Registrations */
+ u32 res1:16;
+ u32 reg_func:8;
+};
+
+/*
+ * Information category for Basic link data
+ */
+enum {
+ FC_CAT_NOP = 0x0,
+ FC_CAT_ABTS = 0x1,
+ FC_CAT_RMC = 0x2,
+ FC_CAT_BA_ACC = 0x4,
+ FC_CAT_BA_RJT = 0x5,
+ FC_CAT_PRMT = 0x6,
+};
+
+/*
+ * LS_RJT els reply payload
+ */
+struct fc_ls_rjt_s {
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 reason_code:8; /* Reason code for reject */
+ u32 reason_code_expl:8; /* Reason code explanation */
+ u32 vendor_unique:8; /* Vendor specific */
+};
+
+/*
+ * LS_RJT reason codes
+ */
+enum {
+ FC_LS_RJT_RSN_INV_CMD_CODE = 0x01,
+ FC_LS_RJT_RSN_LOGICAL_ERROR = 0x03,
+ FC_LS_RJT_RSN_LOGICAL_BUSY = 0x05,
+ FC_LS_RJT_RSN_PROTOCOL_ERROR = 0x07,
+ FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD = 0x09,
+ FC_LS_RJT_RSN_CMD_NOT_SUPP = 0x0B,
+};
+
+/*
+ * LS_RJT reason code explanation
+ */
+enum {
+ FC_LS_RJT_EXP_NO_ADDL_INFO = 0x00,
+ FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS = 0x01,
+ FC_LS_RJT_EXP_SPARMS_ERR_INI_CTL = 0x03,
+ FC_LS_RJT_EXP_SPARMS_ERR_REC_CTL = 0x05,
+ FC_LS_RJT_EXP_SPARMS_ERR_RXSZ = 0x07,
+ FC_LS_RJT_EXP_SPARMS_ERR_CONSEQ = 0x09,
+ FC_LS_RJT_EXP_SPARMS_ERR_CREDIT = 0x0B,
+ FC_LS_RJT_EXP_INV_PORT_NAME = 0x0D,
+ FC_LS_RJT_EXP_INV_NODE_FABRIC_NAME = 0x0E,
+ FC_LS_RJT_EXP_INV_CSP = 0x0F,
+ FC_LS_RJT_EXP_INV_ASSOC_HDR = 0x11,
+ FC_LS_RJT_EXP_ASSOC_HDR_REQD = 0x13,
+ FC_LS_RJT_EXP_INV_ORIG_S_ID = 0x15,
+ FC_LS_RJT_EXP_INV_OXID_RXID_COMB = 0x17,
+ FC_LS_RJT_EXP_CMD_ALREADY_IN_PROG = 0x19,
+ FC_LS_RJT_EXP_LOGIN_REQUIRED = 0x1E,
+ FC_LS_RJT_EXP_INVALID_NPORT_ID = 0x1F,
+ FC_LS_RJT_EXP_INSUFF_RES = 0x29,
+ FC_LS_RJT_EXP_CMD_NOT_SUPP = 0x2C,
+ FC_LS_RJT_EXP_INV_PAYLOAD_LEN = 0x2D,
+};
+
+/*
+ * RRQ els command payload
+ */
+struct fc_rrq_s{
+ struct fc_els_cmd_s els_cmd; /* ELS command code */
+ u32 res1:8;
+ u32 s_id:24; /* exchange originator S_ID */
+
+ u32 ox_id:16; /* originator exchange ID */
+ u32 rx_id:16; /* responder exchange ID */
+
+ u32 res2[8]; /* optional association header */
+};
+
+/*
+ * ABTS BA_ACC reply payload
+ */
+struct fc_ba_acc_s{
+ u32 seq_id_valid:8; /* set to 0x00 for Abort Exchange */
+ u32 seq_id:8; /* invalid for Abort Exchange */
+ u32 res2:16;
+ u32 ox_id:16; /* OX_ID from ABTS frame */
+ u32 rx_id:16; /* RX_ID from ABTS frame */
+ u32 low_seq_cnt:16; /* set to 0x0000 for Abort Exchange */
+ u32 high_seq_cnt:16;/* set to 0xFFFF for Abort Exchange */
+};
+
+/*
+ * ABTS BA_RJT reject payload
+ */
+struct fc_ba_rjt_s{
+ u32 res1:8; /* Reserved */
+ u32 reason_code:8; /* reason code for reject */
+ u32 reason_expl:8; /* reason code explanation */
+ u32 vendor_unique:8;/* vendor unique reason code,set to 0 */
+};
+
+/*
+ * TPRLO logout parameter page
+ */
+struct fc_tprlo_params_page_s{
+ u32 type:8;
+ u32 type_ext:8;
+
+#ifdef __BIGENDIAN
+ u32 opa_valid:1;
+ u32 rpa_valid:1;
+ u32 tpo_nport_valid:1;
+ u32 global_process_logout:1;
+ u32 res1:12;
+#else
+ u32 res1:12;
+ u32 global_process_logout:1;
+ u32 tpo_nport_valid:1;
+ u32 rpa_valid:1;
+ u32 opa_valid:1;
+#endif
+
+ u32 orig_process_assc;
+ u32 resp_process_assc;
+
+ u32 res2:8;
+ u32 tpo_nport_id;
+};
+
+/*
+ * TPRLO ELS command payload
+ */
+struct fc_tprlo_s{
+ u32 command:8;
+ u32 page_len:8;
+ u32 payload_len:16;
+
+ struct fc_tprlo_params_page_s tprlo_params[1];
+};
+
+enum fc_tprlo_type{
+ FC_GLOBAL_LOGO = 1,
+ FC_TPR_LOGO
+};
+
+/*
+ * TPRLO els command ACC payload
+ */
+struct fc_tprlo_acc_s{
+ u32 command:8;
+ u32 page_len:8;
+ u32 payload_len:16;
+ struct fc_prlo_acc_params_page_s tprlo_acc_params[1];
+};
+
+/*
+ * RSCN els command req payload
+ */
+#define FC_RSCN_PGLEN 0x4
+
+enum fc_rscn_format{
+ FC_RSCN_FORMAT_PORTID = 0x0,
+ FC_RSCN_FORMAT_AREA = 0x1,
+ FC_RSCN_FORMAT_DOMAIN = 0x2,
+ FC_RSCN_FORMAT_FABRIC = 0x3,
+};
+
+struct fc_rscn_event_s{
+ u32 format:2;
+ u32 qualifier:4;
+ u32 resvd:2;
+ u32 portid:24;
+};
+
+struct fc_rscn_pl_s{
+ u8 command;
+ u8 pagelen;
+ u16 payldlen;
+ struct fc_rscn_event_s event[1];
+};
+
+/*
+ * ECHO els command req payload
+ */
+struct fc_echo_s {
+ struct fc_els_cmd_s els_cmd;
+};
+
+/*
+ * RNID els command
+ */
+
+#define RNID_NODEID_DATA_FORMAT_COMMON 0x00
+#define RNID_NODEID_DATA_FORMAT_FCP3 0x08
+#define RNID_NODEID_DATA_FORMAT_DISCOVERY 0xDF
+
+#define RNID_ASSOCIATED_TYPE_UNKNOWN 0x00000001
+#define RNID_ASSOCIATED_TYPE_OTHER 0x00000002
+#define RNID_ASSOCIATED_TYPE_HUB 0x00000003
+#define RNID_ASSOCIATED_TYPE_SWITCH 0x00000004
+#define RNID_ASSOCIATED_TYPE_GATEWAY 0x00000005
+#define RNID_ASSOCIATED_TYPE_STORAGE_DEVICE 0x00000009
+#define RNID_ASSOCIATED_TYPE_HOST 0x0000000A
+#define RNID_ASSOCIATED_TYPE_STORAGE_SUBSYSTEM 0x0000000B
+#define RNID_ASSOCIATED_TYPE_STORAGE_ACCESS_DEVICE 0x0000000E
+#define RNID_ASSOCIATED_TYPE_NAS_SERVER 0x00000011
+#define RNID_ASSOCIATED_TYPE_BRIDGE 0x00000002
+#define RNID_ASSOCIATED_TYPE_VIRTUALIZATION_DEVICE 0x00000003
+#define RNID_ASSOCIATED_TYPE_MULTI_FUNCTION_DEVICE 0x000000FF
+
+/*
+ * RNID els command payload
+ */
+struct fc_rnid_cmd_s{
+ struct fc_els_cmd_s els_cmd;
+ u32 node_id_data_format:8;
+ u32 reserved:24;
+};
+
+/*
+ * RNID els response payload
+ */
+
+struct fc_rnid_common_id_data_s{
+ wwn_t port_name;
+ wwn_t node_name;
+};
+
+struct fc_rnid_general_topology_data_s{
+ u32 vendor_unique[4];
+ u32 asso_type;
+ u32 phy_port_num;
+ u32 num_attached_nodes;
+ u32 node_mgmt:8;
+ u32 ip_version:8;
+ u32 udp_tcp_port_num:16;
+ u32 ip_address[4];
+ u32 reserved:16;
+ u32 vendor_specific:16;
+};
+
+struct fc_rnid_acc_s{
+ struct fc_els_cmd_s els_cmd;
+ u32 node_id_data_format:8;
+ u32 common_id_data_length:8;
+ u32 reserved:8;
+ u32 specific_id_data_length:8;
+ struct fc_rnid_common_id_data_s common_id_data;
+ struct fc_rnid_general_topology_data_s gen_topology_data;
+};
+
+#define RNID_ASSOCIATED_TYPE_UNKNOWN 0x00000001
+#define RNID_ASSOCIATED_TYPE_OTHER 0x00000002
+#define RNID_ASSOCIATED_TYPE_HUB 0x00000003
+#define RNID_ASSOCIATED_TYPE_SWITCH 0x00000004
+#define RNID_ASSOCIATED_TYPE_GATEWAY 0x00000005
+#define RNID_ASSOCIATED_TYPE_STORAGE_DEVICE 0x00000009
+#define RNID_ASSOCIATED_TYPE_HOST 0x0000000A
+#define RNID_ASSOCIATED_TYPE_STORAGE_SUBSYSTEM 0x0000000B
+#define RNID_ASSOCIATED_TYPE_STORAGE_ACCESS_DEVICE 0x0000000E
+#define RNID_ASSOCIATED_TYPE_NAS_SERVER 0x00000011
+#define RNID_ASSOCIATED_TYPE_BRIDGE 0x00000002
+#define RNID_ASSOCIATED_TYPE_VIRTUALIZATION_DEVICE 0x00000003
+#define RNID_ASSOCIATED_TYPE_MULTI_FUNCTION_DEVICE 0x000000FF
+
+enum fc_rpsc_speed_cap{
+ RPSC_SPEED_CAP_1G = 0x8000,
+ RPSC_SPEED_CAP_2G = 0x4000,
+ RPSC_SPEED_CAP_4G = 0x2000,
+ RPSC_SPEED_CAP_10G = 0x1000,
+ RPSC_SPEED_CAP_8G = 0x0800,
+ RPSC_SPEED_CAP_16G = 0x0400,
+
+ RPSC_SPEED_CAP_UNKNOWN = 0x0001,
+};
+
+enum fc_rpsc_op_speed_s{
+ RPSC_OP_SPEED_1G = 0x8000,
+ RPSC_OP_SPEED_2G = 0x4000,
+ RPSC_OP_SPEED_4G = 0x2000,
+ RPSC_OP_SPEED_10G = 0x1000,
+ RPSC_OP_SPEED_8G = 0x0800,
+ RPSC_OP_SPEED_16G = 0x0400,
+
+ RPSC_OP_SPEED_NOT_EST = 0x0001, /*! speed not established */
+};
+
+struct fc_rpsc_speed_info_s{
+ u16 port_speed_cap; /*! see fc_rpsc_speed_cap_t */
+ u16 port_op_speed; /*! see fc_rpsc_op_speed_t */
+};
+
+enum link_e2e_beacon_subcmd{
+ LINK_E2E_BEACON_ON = 1,
+ LINK_E2E_BEACON_OFF = 2
+};
+
+enum beacon_type{
+ BEACON_TYPE_NORMAL = 1, /*! Normal Beaconing. Green */
+ BEACON_TYPE_WARN = 2, /*! Warning Beaconing. Yellow/Amber */
+ BEACON_TYPE_CRITICAL = 3 /*! Critical Beaconing. Red */
+};
+
+struct link_e2e_beacon_param_s {
+ u8 beacon_type; /* Beacon Type. See beacon_type_t */
+ u8 beacon_frequency;
+ /* Beacon frequency. Number of blinks
+ * per 10 seconds
+ */
+ u16 beacon_duration;/* Beacon duration (in Seconds). The
+ * command operation should be
+ * terminated at the end of this
+ * timeout value.
+ *
+ * Ignored if diag_sub_cmd is
+ * LINK_E2E_BEACON_OFF.
+ *
+ * If 0, beaconing will continue till a
+ * BEACON OFF request is received
+ */
+};
+
+/*
+ * Link E2E beacon request/good response format. For LS_RJTs use fc_ls_rjt_t
+ */
+struct link_e2e_beacon_req_s{
+ u32 ls_code; /*! FC_ELS_E2E_LBEACON in requests *
+ *or FC_ELS_ACC in good replies */
+ u32 ls_sub_cmd; /*! See link_e2e_beacon_subcmd_t */
+ struct link_e2e_beacon_param_s beacon_parm;
+};
+
+/**
+ * If RPSC request is sent to the Domain Controller, the request is for
+ * all the ports within that domain (TODO - I don't think FOS implements
+ * this...).
+ */
+struct fc_rpsc_cmd_s{
+ struct fc_els_cmd_s els_cmd;
+};
+
+/*
+ * RPSC Acc
+ */
+struct fc_rpsc_acc_s{
+ u32 command:8;
+ u32 rsvd:8;
+ u32 num_entries:16;
+
+ struct fc_rpsc_speed_info_s speed_info[1];
+};
+
+/**
+ * If RPSC2 request is sent to the Domain Controller,
+ */
+#define FC_BRCD_TOKEN 0x42524344
+
+struct fc_rpsc2_cmd_s{
+ struct fc_els_cmd_s els_cmd;
+ u32 token;
+ u16 resvd;
+ u16 num_pids; /* Number of pids in the request */
+ struct {
+ u32 rsvd1:8;
+ u32 pid:24; /* port identifier */
+ } pid_list[1];
+};
+
+enum fc_rpsc2_port_type{
+ RPSC2_PORT_TYPE_UNKNOWN = 0,
+ RPSC2_PORT_TYPE_NPORT = 1,
+ RPSC2_PORT_TYPE_NLPORT = 2,
+ RPSC2_PORT_TYPE_NPIV_PORT = 0x5f,
+ RPSC2_PORT_TYPE_NPORT_TRUNK = 0x6f,
+};
+
+/*
+ * RPSC2 portInfo entry structure
+ */
+struct fc_rpsc2_port_info_s{
+ u32 pid; /* PID */
+ u16 resvd1;
+ u16 index; /* port number / index */
+ u8 resvd2;
+ u8 type; /* port type N/NL/... */
+ u16 speed; /* port Operating Speed */
+};
+
+/*
+ * RPSC2 Accept payload
+ */
+struct fc_rpsc2_acc_s{
+ u8 els_cmd;
+ u8 resvd;
+ u16 num_pids; /* Number of pids in the request */
+ struct fc_rpsc2_port_info_s port_info[1]; /* port information */
+};
+
+/**
+ * bit fields so that multiple classes can be specified
+ */
+enum fc_cos{
+ FC_CLASS_2 = 0x04,
+ FC_CLASS_3 = 0x08,
+ FC_CLASS_2_3 = 0x0C,
+};
+
+/*
+ * symbolic name
+ */
+struct fc_symname_s{
+ u8 symname[FC_SYMNAME_MAX];
+};
+
+struct fc_alpabm_s{
+ u8 alpa_bm[FC_ALPA_MAX / 8];
+};
+
+/*
+ * protocol default timeout values
+ */
+#define FC_ED_TOV 2
+#define FC_REC_TOV (FC_ED_TOV + 1)
+#define FC_RA_TOV 10
+#define FC_ELS_TOV (2 * FC_RA_TOV)
+
+/*
+ * virtual fabric related defines
+ */
+#define FC_VF_ID_NULL 0 /* must not be used as VF_ID */
+#define FC_VF_ID_MIN 1
+#define FC_VF_ID_MAX 0xEFF
+#define FC_VF_ID_CTL 0xFEF /* control VF_ID */
+
+/**
+ * Virtual Fabric Tagging header format
+ * @caution This is defined only in BIG ENDIAN format.
+ */
+struct fc_vft_s{
+ u32 r_ctl:8;
+ u32 ver:2;
+ u32 type:4;
+ u32 res_a:2;
+ u32 priority:3;
+ u32 vf_id:12;
+ u32 res_b:1;
+ u32 hopct:8;
+ u32 res_c:24;
+};
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/fc_sp.h b/drivers/scsi/bfa/include/protocol/fc_sp.h
new file mode 100644
index 000000000000..55bb0b31d04b
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/fc_sp.h
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __FC_SP_H__
+#define __FC_SP_H__
+
+#include <protocol/types.h>
+
+#pragma pack(1)
+
+enum auth_els_flags{
+ FC_AUTH_ELS_MORE_FRAGS_FLAG = 0x80, /*! bit-7. More Fragments
+ * Follow
+ */
+ FC_AUTH_ELS_CONCAT_FLAG = 0x40, /*! bit-6. Concatenation Flag */
+ FC_AUTH_ELS_SEQ_NUM_FLAG = 0x01 /*! bit-0. Sequence Number */
+};
+
+enum auth_msg_codes{
+ FC_AUTH_MC_AUTH_RJT = 0x0A, /*! Auth Reject */
+ FC_AUTH_MC_AUTH_NEG = 0x0B, /*! Auth Negotiate */
+ FC_AUTH_MC_AUTH_DONE = 0x0C, /*! Auth Done */
+
+ FC_AUTH_MC_DHCHAP_CHAL = 0x10, /*! DHCHAP Challenge */
+ FC_AUTH_MC_DHCHAP_REPLY = 0x11, /*! DHCHAP Reply */
+ FC_AUTH_MC_DHCHAP_SUCC = 0x12, /*! DHCHAP Success */
+
+ FC_AUTH_MC_FCAP_REQ = 0x13, /*! FCAP Request */
+ FC_AUTH_MC_FCAP_ACK = 0x14, /*! FCAP Acknowledge */
+ FC_AUTH_MC_FCAP_CONF = 0x15, /*! FCAP Confirm */
+
+ FC_AUTH_MC_FCPAP_INIT = 0x16, /*! FCPAP Init */
+ FC_AUTH_MC_FCPAP_ACC = 0x17, /*! FCPAP Accept */
+ FC_AUTH_MC_FCPAP_COMP = 0x18, /*! FCPAP Complete */
+
+ FC_AUTH_MC_IKE_SA_INIT = 0x22, /*! IKE SA INIT */
+ FC_AUTH_MC_IKE_SA_AUTH = 0x23, /*! IKE SA Auth */
+ FC_AUTH_MC_IKE_CREATE_CHILD_SA = 0x24, /*! IKE Create Child SA */
+ FC_AUTH_MC_IKE_INFO = 0x25, /*! IKE informational */
+};
+
+enum auth_proto_version{
+ FC_AUTH_PROTO_VER_1 = 1, /*! Protocol Version 1 */
+};
+
+enum {
+ FC_AUTH_ELS_COMMAND_CODE = 0x90,/*! Authentication ELS Command code */
+ FC_AUTH_PROTO_PARAM_LEN_SZ = 4, /*! Size of Proto Parameter Len Field */
+ FC_AUTH_PROTO_PARAM_VAL_SZ = 4, /*! Size of Proto Parameter Val Field */
+ FC_MAX_AUTH_SECRET_LEN = 256,
+ /*! Maximum secret string length */
+ FC_AUTH_NUM_USABLE_PROTO_LEN_SZ = 4,
+ /*! Size of usable protocols field */
+ FC_AUTH_RESP_VALUE_LEN_SZ = 4,
+ /*! Size of response value length */
+ FC_MAX_CHAP_KEY_LEN = 256, /*! Maximum md5 digest length */
+ FC_MAX_AUTH_RETRIES = 3, /*! Maximum number of retries */
+ FC_MD5_DIGEST_LEN = 16, /*! MD5 digest length */
+ FC_SHA1_DIGEST_LEN = 20, /*! SHA1 digest length */
+ FC_MAX_DHG_SUPPORTED = 1, /*! Maximum DH Groups supported */
+ FC_MAX_ALG_SUPPORTED = 1, /*! Maximum algorithms supported */
+ FC_MAX_PROTO_SUPPORTED = 1, /*! Maximum protocols supported */
+ FC_START_TXN_ID = 2, /*! Starting transaction ID */
+};
+
+enum auth_proto_id{
+ FC_AUTH_PROTO_DHCHAP = 0x00000001,
+ FC_AUTH_PROTO_FCAP = 0x00000002,
+ FC_AUTH_PROTO_FCPAP = 0x00000003,
+ FC_AUTH_PROTO_IKEv2 = 0x00000004,
+ FC_AUTH_PROTO_IKEv2_AUTH = 0x00000005,
+};
+
+struct auth_name_s{
+ u16 name_tag; /*! Name Tag = 1 for Authentication */
+ u16 name_len; /*! Name Length = 8 for Authentication
+ */
+ wwn_t name; /*! Name. TODO - is this PWWN */
+};
+
+
+enum auth_hash_func{
+ FC_AUTH_HASH_FUNC_MD5 = 0x00000005,
+ FC_AUTH_HASH_FUNC_SHA_1 = 0x00000006,
+};
+
+enum auth_dh_gid{
+ FC_AUTH_DH_GID_0_DHG_NULL = 0x00000000,
+ FC_AUTH_DH_GID_1_DHG_1024 = 0x00000001,
+ FC_AUTH_DH_GID_2_DHG_1280 = 0x00000002,
+ FC_AUTH_DH_GID_3_DHG_1536 = 0x00000003,
+ FC_AUTH_DH_GID_4_DHG_2048 = 0x00000004,
+ FC_AUTH_DH_GID_6_DHG_3072 = 0x00000006,
+ FC_AUTH_DH_GID_7_DHG_4096 = 0x00000007,
+ FC_AUTH_DH_GID_8_DHG_6144 = 0x00000008,
+ FC_AUTH_DH_GID_9_DHG_8192 = 0x00000009,
+};
+
+struct auth_els_msg_s {
+ u8 auth_els_code; /* Authentication ELS Code (0x90) */
+ u8 auth_els_flag; /* Authentication ELS Flags */
+ u8 auth_msg_code; /* Authentication Message Code */
+ u8 proto_version; /* Protocol Version */
+ u32 msg_len; /* Message Length */
+ u32 trans_id; /* Transaction Identifier (T_ID) */
+
+ /* Msg payload follows... */
+};
+
+
+enum auth_neg_param_tags {
+ FC_AUTH_NEG_DHCHAP_HASHLIST = 0x0001,
+ FC_AUTH_NEG_DHCHAP_DHG_ID_LIST = 0x0002,
+};
+
+
+struct dhchap_param_format_s {
+ u16 tag; /*! Parameter Tag. See
+ * auth_neg_param_tags_t
+ */
+ u16 word_cnt;
+
+ /* followed by variable length parameter value... */
+};
+
+struct auth_proto_params_s {
+ u32 proto_param_len;
+ u32 proto_id;
+
+ /*
+ * Followed by variable length Protocol specific parameters. DH-CHAP
+ * uses dhchap_param_format_t
+ */
+};
+
+struct auth_neg_msg_s {
+ struct auth_name_s auth_ini_name;
+ u32 usable_auth_protos;
+ struct auth_proto_params_s proto_params[1]; /*! (1..usable_auth_proto)
+ * protocol params
+ */
+};
+
+struct auth_dh_val_s {
+ u32 dh_val_len;
+ u32 dh_val[1];
+};
+
+struct auth_dhchap_chal_msg_s {
+ struct auth_els_msg_s hdr;
+ struct auth_name_s auth_responder_name; /* TODO VRK - is auth_name_t
+ * type OK?
+ */
+ u32 hash_id;
+ u32 dh_grp_id;
+ u32 chal_val_len;
+ char chal_val[1];
+
+ /* ...followed by variable Challenge length/value and DH length/value */
+};
+
+
+enum auth_rjt_codes {
+ FC_AUTH_RJT_CODE_AUTH_FAILURE = 0x01,
+ FC_AUTH_RJT_CODE_LOGICAL_ERR = 0x02,
+};
+
+enum auth_rjt_code_exps {
+ FC_AUTH_CEXP_AUTH_MECH_NOT_USABLE = 0x01,
+ FC_AUTH_CEXP_DH_GROUP_NOT_USABLE = 0x02,
+ FC_AUTH_CEXP_HASH_FUNC_NOT_USABLE = 0x03,
+ FC_AUTH_CEXP_AUTH_XACT_STARTED = 0x04,
+ FC_AUTH_CEXP_AUTH_FAILED = 0x05,
+ FC_AUTH_CEXP_INCORRECT_PLD = 0x06,
+ FC_AUTH_CEXP_INCORRECT_PROTO_MSG = 0x07,
+ FC_AUTH_CEXP_RESTART_AUTH_PROTO = 0x08,
+ FC_AUTH_CEXP_AUTH_CONCAT_NOT_SUPP = 0x09,
+ FC_AUTH_CEXP_PROTO_VER_NOT_SUPP = 0x0A,
+};
+
+enum auth_status {
+ FC_AUTH_STATE_INPROGRESS = 0, /*! authentication in progress */
+ FC_AUTH_STATE_FAILED = 1, /*! authentication failed */
+ FC_AUTH_STATE_SUCCESS = 2 /*! authentication successful */
+};
+
+struct auth_rjt_msg_s {
+ struct auth_els_msg_s hdr;
+ u8 reason_code;
+ u8 reason_code_exp;
+ u8 rsvd[2];
+};
+
+
+struct auth_dhchap_neg_msg_s {
+ struct auth_els_msg_s hdr;
+ struct auth_neg_msg_s nego;
+};
+
+struct auth_dhchap_reply_msg_s {
+ struct auth_els_msg_s hdr;
+
+ /*
+ * followed by response value length & Value + DH Value Length & Value
+ */
+};
+
+#pragma pack()
+
+#endif /* __FC_SP_H__ */
diff --git a/drivers/scsi/bfa/include/protocol/fcp.h b/drivers/scsi/bfa/include/protocol/fcp.h
new file mode 100644
index 000000000000..9ade68ad2853
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/fcp.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __FCPPROTO_H__
+#define __FCPPROTO_H__
+
+#include <protocol/scsi.h>
+
+#pragma pack(1)
+
+enum {
+ FCP_RJT = 0x01000000, /* SRR reject */
+ FCP_SRR_ACCEPT = 0x02000000, /* SRR accept */
+ FCP_SRR = 0x14000000, /* Sequence Retransmission Request */
+};
+
+/*
+ * SRR FC-4 LS payload
+ */
+struct fc_srr_s{
+ u32 ls_cmd;
+ u32 ox_id:16; /* ox-id */
+ u32 rx_id:16; /* rx-id */
+ u32 ro; /* relative offset */
+ u32 r_ctl:8; /* R_CTL for I.U. */
+ u32 res:24;
+};
+
+
+/*
+ * FCP_CMND definitions
+ */
+#define FCP_CMND_CDB_LEN 16
+#define FCP_CMND_LUN_LEN 8
+
+struct fcp_cmnd_s{
+ lun_t lun; /* 64-bit LU number */
+ u8 crn; /* command reference number */
+#ifdef __BIGENDIAN
+ u8 resvd:1,
+ priority:4, /* FCP-3: SAM-3 priority */
+ taskattr:3; /* scsi task attribute */
+#else
+ u8 taskattr:3, /* scsi task attribute */
+ priority:4, /* FCP-3: SAM-3 priority */
+ resvd:1;
+#endif
+ u8 tm_flags; /* task management flags */
+#ifdef __BIGENDIAN
+ u8 addl_cdb_len:6, /* additional CDB length words */
+ iodir:2; /* read/write FCP_DATA IUs */
+#else
+ u8 iodir:2, /* read/write FCP_DATA IUs */
+ addl_cdb_len:6; /* additional CDB length */
+#endif
+ struct scsi_cdb_s cdb;
+
+ /*
+ * !!! additional cdb bytes follows here!!!
+ */
+ u32 fcp_dl; /* bytes to be transferred */
+};
+
+#define fcp_cmnd_cdb_len(_cmnd) ((_cmnd)->addl_cdb_len * 4 + FCP_CMND_CDB_LEN)
+#define fcp_cmnd_fcpdl(_cmnd) ((&(_cmnd)->fcp_dl)[(_cmnd)->addl_cdb_len])
+
+/*
+ * fcp_cmnd_t.iodir field values
+ */
+enum fcp_iodir{
+ FCP_IODIR_NONE = 0,
+ FCP_IODIR_WRITE = 1,
+ FCP_IODIR_READ = 2,
+ FCP_IODIR_RW = 3,
+};
+
+/*
+ * Task attribute field
+ */
+enum {
+ FCP_TASK_ATTR_SIMPLE = 0,
+ FCP_TASK_ATTR_HOQ = 1,
+ FCP_TASK_ATTR_ORDERED = 2,
+ FCP_TASK_ATTR_ACA = 4,
+ FCP_TASK_ATTR_UNTAGGED = 5, /* obsolete in FCP-3 */
+};
+
+/*
+ * Task management flags field - only one bit shall be set
+ */
+#ifndef BIT
+#define BIT(_x) (1 << (_x))
+#endif
+enum fcp_tm_cmnd{
+ FCP_TM_ABORT_TASK_SET = BIT(1),
+ FCP_TM_CLEAR_TASK_SET = BIT(2),
+ FCP_TM_LUN_RESET = BIT(4),
+ FCP_TM_TARGET_RESET = BIT(5), /* obsolete in FCP-3 */
+ FCP_TM_CLEAR_ACA = BIT(6),
+};
+
+/*
+ * FCP_XFER_RDY IU defines
+ */
+struct fcp_xfer_rdy_s{
+ u32 data_ro;
+ u32 burst_len;
+ u32 reserved;
+};
+
+/*
+ * FCP_RSP residue flags
+ */
+enum fcp_residue{
+ FCP_NO_RESIDUE = 0, /* no residue */
+ FCP_RESID_OVER = 1, /* more data left that was not sent */
+ FCP_RESID_UNDER = 2, /* less data than requested */
+};
+
+enum {
+ FCP_RSPINFO_GOOD = 0,
+ FCP_RSPINFO_DATALEN_MISMATCH = 1,
+ FCP_RSPINFO_CMND_INVALID = 2,
+ FCP_RSPINFO_ROLEN_MISMATCH = 3,
+ FCP_RSPINFO_TM_NOT_SUPP = 4,
+ FCP_RSPINFO_TM_FAILED = 5,
+};
+
+struct fcp_rspinfo_s{
+ u32 res0:24;
+ u32 rsp_code:8; /* response code (as above) */
+ u32 res1;
+};
+
+struct fcp_resp_s{
+ u32 reserved[2]; /* 2 words reserved */
+ u16 reserved2;
+#ifdef __BIGENDIAN
+ u8 reserved3:3;
+ u8 fcp_conf_req:1; /* FCP_CONF is requested */
+ u8 resid_flags:2; /* underflow/overflow */
+ u8 sns_len_valid:1;/* sense len is valid */
+ u8 rsp_len_valid:1;/* response len is valid */
+#else
+ u8 rsp_len_valid:1;/* response len is valid */
+ u8 sns_len_valid:1;/* sense len is valid */
+ u8 resid_flags:2; /* underflow/overflow */
+ u8 fcp_conf_req:1; /* FCP_CONF is requested */
+ u8 reserved3:3;
+#endif
+ u8 scsi_status; /* one byte SCSI status */
+ u32 residue; /* residual data bytes */
+ u32 sns_len; /* length od sense info */
+ u32 rsp_len; /* length of response info */
+};
+
+#define fcp_snslen(__fcprsp) ((__fcprsp)->sns_len_valid ? \
+ (__fcprsp)->sns_len : 0)
+#define fcp_rsplen(__fcprsp) ((__fcprsp)->rsp_len_valid ? \
+ (__fcprsp)->rsp_len : 0)
+#define fcp_rspinfo(__fcprsp) ((struct fcp_rspinfo_s *)((__fcprsp) + 1))
+#define fcp_snsinfo(__fcprsp) (((u8 *)fcp_rspinfo(__fcprsp)) + \
+ fcp_rsplen(__fcprsp))
+
+struct fcp_cmnd_fr_s{
+ struct fchs_s fchs;
+ struct fcp_cmnd_s fcp;
+};
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/fdmi.h b/drivers/scsi/bfa/include/protocol/fdmi.h
new file mode 100644
index 000000000000..6c05c268c71b
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/fdmi.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __FDMI_H__
+#define __FDMI_H__
+
+#include <protocol/types.h>
+#include <protocol/fc.h>
+#include <protocol/ct.h>
+
+#pragma pack(1)
+
+/*
+ * FDMI Command Codes
+ */
+#define FDMI_GRHL 0x0100
+#define FDMI_GHAT 0x0101
+#define FDMI_GRPL 0x0102
+#define FDMI_GPAT 0x0110
+#define FDMI_RHBA 0x0200
+#define FDMI_RHAT 0x0201
+#define FDMI_RPRT 0x0210
+#define FDMI_RPA 0x0211
+#define FDMI_DHBA 0x0300
+#define FDMI_DPRT 0x0310
+
+/*
+ * FDMI reason codes
+ */
+#define FDMI_NO_ADDITIONAL_EXP 0x00
+#define FDMI_HBA_ALREADY_REG 0x10
+#define FDMI_HBA_ATTRIB_NOT_REG 0x11
+#define FDMI_HBA_ATTRIB_MULTIPLE 0x12
+#define FDMI_HBA_ATTRIB_LENGTH_INVALID 0x13
+#define FDMI_HBA_ATTRIB_NOT_PRESENT 0x14
+#define FDMI_PORT_ORIG_NOT_IN_LIST 0x15
+#define FDMI_PORT_HBA_NOT_IN_LIST 0x16
+#define FDMI_PORT_ATTRIB_NOT_REG 0x20
+#define FDMI_PORT_NOT_REG 0x21
+#define FDMI_PORT_ATTRIB_MULTIPLE 0x22
+#define FDMI_PORT_ATTRIB_LENGTH_INVALID 0x23
+#define FDMI_PORT_ALREADY_REGISTEREED 0x24
+
+/*
+ * FDMI Transmission Speed Mask values
+ */
+#define FDMI_TRANS_SPEED_1G 0x00000001
+#define FDMI_TRANS_SPEED_2G 0x00000002
+#define FDMI_TRANS_SPEED_10G 0x00000004
+#define FDMI_TRANS_SPEED_4G 0x00000008
+#define FDMI_TRANS_SPEED_8G 0x00000010
+#define FDMI_TRANS_SPEED_16G 0x00000020
+#define FDMI_TRANS_SPEED_UNKNOWN 0x00008000
+
+/*
+ * FDMI HBA attribute types
+ */
+enum fdmi_hba_attribute_type {
+ FDMI_HBA_ATTRIB_NODENAME = 1, /* 0x0001 */
+ FDMI_HBA_ATTRIB_MANUFACTURER, /* 0x0002 */
+ FDMI_HBA_ATTRIB_SERIALNUM, /* 0x0003 */
+ FDMI_HBA_ATTRIB_MODEL, /* 0x0004 */
+ FDMI_HBA_ATTRIB_MODEL_DESC, /* 0x0005 */
+ FDMI_HBA_ATTRIB_HW_VERSION, /* 0x0006 */
+ FDMI_HBA_ATTRIB_DRIVER_VERSION, /* 0x0007 */
+ FDMI_HBA_ATTRIB_ROM_VERSION, /* 0x0008 */
+ FDMI_HBA_ATTRIB_FW_VERSION, /* 0x0009 */
+ FDMI_HBA_ATTRIB_OS_NAME, /* 0x000A */
+ FDMI_HBA_ATTRIB_MAX_CT, /* 0x000B */
+
+ FDMI_HBA_ATTRIB_MAX_TYPE
+};
+
+/*
+ * FDMI Port attribute types
+ */
+enum fdmi_port_attribute_type {
+ FDMI_PORT_ATTRIB_FC4_TYPES = 1, /* 0x0001 */
+ FDMI_PORT_ATTRIB_SUPP_SPEED, /* 0x0002 */
+ FDMI_PORT_ATTRIB_PORT_SPEED, /* 0x0003 */
+ FDMI_PORT_ATTRIB_FRAME_SIZE, /* 0x0004 */
+ FDMI_PORT_ATTRIB_DEV_NAME, /* 0x0005 */
+ FDMI_PORT_ATTRIB_HOST_NAME, /* 0x0006 */
+
+ FDMI_PORT_ATTR_MAX_TYPE
+};
+
+/*
+ * FDMI attribute
+ */
+struct fdmi_attr_s {
+ u16 type;
+ u16 len;
+ u8 value[1];
+};
+
+/*
+ * HBA Attribute Block
+ */
+struct fdmi_hba_attr_s {
+ u32 attr_count; /* # of attributes */
+ struct fdmi_attr_s hba_attr; /* n attributes */
+};
+
+/*
+ * Registered Port List
+ */
+struct fdmi_port_list_s {
+ u32 num_ports; /* number Of Port Entries */
+ wwn_t port_entry; /* one or more */
+};
+
+/*
+ * Port Attribute Block
+ */
+struct fdmi_port_attr_s {
+ u32 attr_count; /* # of attributes */
+ struct fdmi_attr_s port_attr; /* n attributes */
+};
+
+/*
+ * FDMI Register HBA Attributes
+ */
+struct fdmi_rhba_s {
+ wwn_t hba_id; /* HBA Identifier */
+ struct fdmi_port_list_s port_list; /* Registered Port List */
+ struct fdmi_hba_attr_s hba_attr_blk; /* HBA attribute block */
+};
+
+/*
+ * FDMI Register Port
+ */
+struct fdmi_rprt_s {
+ wwn_t hba_id; /* HBA Identifier */
+ wwn_t port_name; /* Port wwn */
+ struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */
+};
+
+/*
+ * FDMI Register Port Attributes
+ */
+struct fdmi_rpa_s {
+ wwn_t port_name; /* port wwn */
+ struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */
+};
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/pcifw.h b/drivers/scsi/bfa/include/protocol/pcifw.h
new file mode 100644
index 000000000000..6830dc3ee58a
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/pcifw.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * pcifw.h PCI FW related headers
+ */
+
+#ifndef __PCIFW_H__
+#define __PCIFW_H__
+
+#pragma pack(1)
+
+struct pnp_hdr_s{
+ u32 signature; /* "$PnP" */
+ u8 rev; /* Struct revision */
+ u8 len; /* Header structure len in multiples
+ * of 16 bytes */
+ u16 off; /* Offset to next header 00 if none */
+ u8 rsvd; /* Reserved byte */
+ u8 cksum; /* 8-bit checksum for this header */
+ u32 pnp_dev_id; /* PnP Device Id */
+ u16 mfstr; /* Pointer to manufacturer string */
+ u16 prstr; /* Pointer to product string */
+ u8 devtype[3]; /* Device Type Code */
+ u8 devind; /* Device Indicator */
+ u16 bcventr; /* Bootstrap entry vector */
+ u16 rsvd2; /* Reserved */
+ u16 sriv; /* Static resource information vector */
+};
+
+struct pci_3_0_ds_s{
+ u32 sig; /* Signature "PCIR" */
+ u16 vendid; /* Vendor ID */
+ u16 devid; /* Device ID */
+ u16 devlistoff; /* Device List Offset */
+ u16 len; /* PCI Data Structure Length */
+ u8 rev; /* PCI Data Structure Revision */
+ u8 clcode[3]; /* Class Code */
+ u16 imglen; /* Code image length in multiples of
+ * 512 bytes */
+ u16 coderev; /* Revision level of code/data */
+ u8 codetype; /* Code type 0x00 - BIOS */
+ u8 indr; /* Last image indicator */
+ u16 mrtimglen; /* Max Run Time Image Length */
+ u16 cuoff; /* Config Utility Code Header Offset */
+ u16 dmtfclp; /* DMTF CLP entry point offset */
+};
+
+struct pci_optrom_hdr_s{
+ u16 sig; /* Signature 0x55AA */
+ u8 len; /* Option ROM length in units of 512 bytes */
+ u8 inivec[3]; /* Initialization vector */
+ u8 rsvd[16]; /* Reserved field */
+ u16 verptr; /* Pointer to version string - private */
+ u16 pcids; /* Pointer to PCI data structure */
+ u16 pnphdr; /* Pointer to PnP expansion header */
+};
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/include/protocol/scsi.h b/drivers/scsi/bfa/include/protocol/scsi.h
new file mode 100644
index 000000000000..b220e6b4f6e1
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/scsi.h
@@ -0,0 +1,1648 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __SCSI_H__
+#define __SCSI_H__
+
+#include <protocol/types.h>
+
+#pragma pack(1)
+
+/*
+ * generic SCSI cdb definition
+ */
+#define SCSI_MAX_CDBLEN 16
+struct scsi_cdb_s{
+ u8 scsi_cdb[SCSI_MAX_CDBLEN];
+};
+
+/*
+ * scsi lun serial number definition
+ */
+#define SCSI_LUN_SN_LEN 32
+struct scsi_lun_sn_s{
+ u8 lun_sn[SCSI_LUN_SN_LEN];
+};
+
+/*
+ * SCSI Direct Access Commands
+ */
+enum {
+ SCSI_OP_TEST_UNIT_READY = 0x00,
+ SCSI_OP_REQUEST_SENSE = 0x03,
+ SCSI_OP_FORMAT_UNIT = 0x04,
+ SCSI_OP_READ6 = 0x08,
+ SCSI_OP_WRITE6 = 0x0A,
+ SCSI_OP_WRITE_FILEMARKS = 0x10,
+ SCSI_OP_INQUIRY = 0x12,
+ SCSI_OP_MODE_SELECT6 = 0x15,
+ SCSI_OP_RESERVE6 = 0x16,
+ SCSI_OP_RELEASE6 = 0x17,
+ SCSI_OP_MODE_SENSE6 = 0x1A,
+ SCSI_OP_START_STOP_UNIT = 0x1B,
+ SCSI_OP_SEND_DIAGNOSTIC = 0x1D,
+ SCSI_OP_READ_CAPACITY = 0x25,
+ SCSI_OP_READ10 = 0x28,
+ SCSI_OP_WRITE10 = 0x2A,
+ SCSI_OP_VERIFY10 = 0x2F,
+ SCSI_OP_READ_DEFECT_DATA = 0x37,
+ SCSI_OP_LOG_SELECT = 0x4C,
+ SCSI_OP_LOG_SENSE = 0x4D,
+ SCSI_OP_MODE_SELECT10 = 0x55,
+ SCSI_OP_RESERVE10 = 0x56,
+ SCSI_OP_RELEASE10 = 0x57,
+ SCSI_OP_MODE_SENSE10 = 0x5A,
+ SCSI_OP_PER_RESERVE_IN = 0x5E,
+ SCSI_OP_PER_RESERVE_OUR = 0x5E,
+ SCSI_OP_READ16 = 0x88,
+ SCSI_OP_WRITE16 = 0x8A,
+ SCSI_OP_VERIFY16 = 0x8F,
+ SCSI_OP_READ_CAPACITY16 = 0x9E,
+ SCSI_OP_REPORT_LUNS = 0xA0,
+ SCSI_OP_READ12 = 0xA8,
+ SCSI_OP_WRITE12 = 0xAA,
+ SCSI_OP_UNDEF = 0xFF,
+};
+
+/*
+ * SCSI START_STOP_UNIT command
+ */
+struct scsi_start_stop_unit_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 reserved1:4;
+ u8 immed:1;
+#else
+ u8 immed:1;
+ u8 reserved1:4;
+ u8 lun:3;
+#endif
+ u8 reserved2;
+ u8 reserved3;
+#ifdef __BIGENDIAN
+ u8 power_conditions:4;
+ u8 reserved4:2;
+ u8 loEj:1;
+ u8 start:1;
+#else
+ u8 start:1;
+ u8 loEj:1;
+ u8 reserved4:2;
+ u8 power_conditions:4;
+#endif
+ u8 control;
+};
+
+/*
+ * SCSI SEND_DIAGNOSTIC command
+ */
+struct scsi_send_diagnostic_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 self_test_code:3;
+ u8 pf:1;
+ u8 reserved1:1;
+ u8 self_test:1;
+ u8 dev_offl:1;
+ u8 unit_offl:1;
+#else
+ u8 unit_offl:1;
+ u8 dev_offl:1;
+ u8 self_test:1;
+ u8 reserved1:1;
+ u8 pf:1;
+ u8 self_test_code:3;
+#endif
+ u8 reserved2;
+
+ u8 param_list_length[2]; /* MSB first */
+ u8 control;
+
+};
+
+/*
+ * SCSI READ10/WRITE10 commands
+ */
+struct scsi_rw10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 dpo:1; /* Disable Page Out */
+ u8 fua:1; /* Force Unit Access */
+ u8 reserved1:2;
+ u8 rel_adr:1; /* relative address */
+#else
+ u8 rel_adr:1;
+ u8 reserved1:2;
+ u8 fua:1;
+ u8 dpo:1;
+ u8 lun:3;
+#endif
+ u8 lba0; /* logical block address - MSB */
+ u8 lba1;
+ u8 lba2;
+ u8 lba3; /* LSB */
+ u8 reserved3;
+ u8 xfer_length0; /* transfer length in blocks - MSB */
+ u8 xfer_length1; /* LSB */
+ u8 control;
+};
+
+#define SCSI_CDB10_GET_LBA(cdb) \
+ (((cdb)->lba0 << 24) | ((cdb)->lba1 << 16) | \
+ ((cdb)->lba2 << 8) | (cdb)->lba3)
+
+#define SCSI_CDB10_SET_LBA(cdb, lba) { \
+ (cdb)->lba0 = lba >> 24; \
+ (cdb)->lba1 = (lba >> 16) & 0xFF; \
+ (cdb)->lba2 = (lba >> 8) & 0xFF; \
+ (cdb)->lba3 = lba & 0xFF; \
+}
+
+#define SCSI_CDB10_GET_TL(cdb) \
+ ((cdb)->xfer_length0 << 8 | (cdb)->xfer_length1)
+#define SCSI_CDB10_SET_TL(cdb, tl) { \
+ (cdb)->xfer_length0 = tl >> 8; \
+ (cdb)->xfer_length1 = tl & 0xFF; \
+}
+
+/*
+ * SCSI READ6/WRITE6 commands
+ */
+struct scsi_rw6_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 lba0:5; /* MSb */
+#else
+ u8 lba0:5; /* MSb */
+ u8 lun:3;
+#endif
+ u8 lba1;
+ u8 lba2; /* LSB */
+ u8 xfer_length;
+ u8 control;
+};
+
+#define SCSI_TAPE_CDB6_GET_TL(cdb) \
+ (((cdb)->tl0 << 16) | ((cdb)->tl1 << 8) | (cdb)->tl2)
+
+#define SCSI_TAPE_CDB6_SET_TL(cdb, tl) { \
+ (cdb)->tl0 = tl >> 16; \
+ (cdb)->tl1 = (tl >> 8) & 0xFF; \
+ (cdb)->tl2 = tl & 0xFF; \
+}
+
+/*
+ * SCSI sequential (TAPE) wrtie command
+ */
+struct scsi_tape_wr_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 rsvd:7;
+ u8 fixed:1; /* MSb */
+#else
+ u8 fixed:1; /* MSb */
+ u8 rsvd:7;
+#endif
+ u8 tl0; /* Msb */
+ u8 tl1;
+ u8 tl2; /* Lsb */
+
+ u8 control;
+};
+
+#define SCSI_CDB6_GET_LBA(cdb) \
+ (((cdb)->lba0 << 16) | ((cdb)->lba1 << 8) | (cdb)->lba2)
+
+#define SCSI_CDB6_SET_LBA(cdb, lba) { \
+ (cdb)->lba0 = lba >> 16; \
+ (cdb)->lba1 = (lba >> 8) & 0xFF; \
+ (cdb)->lba2 = lba & 0xFF; \
+}
+
+#define SCSI_CDB6_GET_TL(cdb) ((cdb)->xfer_length)
+#define SCSI_CDB6_SET_TL(cdb, tl) { \
+ (cdb)->xfer_length = tl; \
+}
+
+/*
+ * SCSI sense data format
+ */
+struct scsi_sense_s{
+#ifdef __BIGENDIAN
+ u8 valid:1;
+ u8 rsp_code:7;
+#else
+ u8 rsp_code:7;
+ u8 valid:1;
+#endif
+ u8 seg_num;
+#ifdef __BIGENDIAN
+ u8 file_mark:1;
+ u8 eom:1; /* end of media */
+ u8 ili:1; /* incorrect length indicator */
+ u8 reserved:1;
+ u8 sense_key:4;
+#else
+ u8 sense_key:4;
+ u8 reserved:1;
+ u8 ili:1; /* incorrect length indicator */
+ u8 eom:1; /* end of media */
+ u8 file_mark:1;
+#endif
+ u8 information[4]; /* device-type or command specific info
+ */
+ u8 add_sense_length;
+ /* additional sense length */
+ u8 command_info[4];/* command specific information
+ */
+ u8 asc; /* additional sense code */
+ u8 ascq; /* additional sense code qualifier */
+ u8 fru_code; /* field replaceable unit code */
+#ifdef __BIGENDIAN
+ u8 sksv:1; /* sense key specific valid */
+ u8 c_d:1; /* command/data bit */
+ u8 res1:2;
+ u8 bpv:1; /* bit pointer valid */
+ u8 bpointer:3; /* bit pointer */
+#else
+ u8 bpointer:3; /* bit pointer */
+ u8 bpv:1; /* bit pointer valid */
+ u8 res1:2;
+ u8 c_d:1; /* command/data bit */
+ u8 sksv:1; /* sense key specific valid */
+#endif
+ u8 fpointer[2]; /* field pointer */
+};
+
+#define SCSI_SENSE_CUR_ERR 0x70
+#define SCSI_SENSE_DEF_ERR 0x71
+
+/*
+ * SCSI sense key values
+ */
+#define SCSI_SK_NO_SENSE 0x0
+#define SCSI_SK_REC_ERR 0x1 /* recovered error */
+#define SCSI_SK_NOT_READY 0x2
+#define SCSI_SK_MED_ERR 0x3 /* medium error */
+#define SCSI_SK_HW_ERR 0x4 /* hardware error */
+#define SCSI_SK_ILLEGAL_REQ 0x5
+#define SCSI_SK_UNIT_ATT 0x6 /* unit attention */
+#define SCSI_SK_DATA_PROTECT 0x7
+#define SCSI_SK_BLANK_CHECK 0x8
+#define SCSI_SK_VENDOR_SPEC 0x9
+#define SCSI_SK_COPY_ABORTED 0xA
+#define SCSI_SK_ABORTED_CMND 0xB
+#define SCSI_SK_VOL_OVERFLOW 0xD
+#define SCSI_SK_MISCOMPARE 0xE
+
+/*
+ * SCSI additional sense codes
+ */
+#define SCSI_ASC_NO_ADD_SENSE 0x00
+#define SCSI_ASC_LUN_NOT_READY 0x04
+#define SCSI_ASC_LUN_COMMUNICATION 0x08
+#define SCSI_ASC_WRITE_ERROR 0x0C
+#define SCSI_ASC_INVALID_CMND_CODE 0x20
+#define SCSI_ASC_BAD_LBA 0x21
+#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24
+#define SCSI_ASC_LUN_NOT_SUPPORTED 0x25
+#define SCSI_ASC_LUN_WRITE_PROTECT 0x27
+#define SCSI_ASC_POWERON_BDR 0x29 /* power on reset, bus reset,
+ * bus device reset
+ */
+#define SCSI_ASC_PARAMS_CHANGED 0x2A
+#define SCSI_ASC_CMND_CLEARED_BY_A_I 0x2F
+#define SCSI_ASC_SAVING_PARAM_NOTSUPP 0x39
+#define SCSI_ASC_TOCC 0x3F /* target operating condtions
+ * changed
+ */
+#define SCSI_ASC_PARITY_ERROR 0x47
+#define SCSI_ASC_CMND_PHASE_ERROR 0x4A
+#define SCSI_ASC_DATA_PHASE_ERROR 0x4B
+#define SCSI_ASC_VENDOR_SPEC 0x7F
+
+/*
+ * SCSI additional sense code qualifiers
+ */
+#define SCSI_ASCQ_CAUSE_NOT_REPORT 0x00
+#define SCSI_ASCQ_BECOMING_READY 0x01
+#define SCSI_ASCQ_INIT_CMD_REQ 0x02
+#define SCSI_ASCQ_FORMAT_IN_PROGRESS 0x04
+#define SCSI_ASCQ_OPERATION_IN_PROGRESS 0x07
+#define SCSI_ASCQ_SELF_TEST_IN_PROGRESS 0x09
+#define SCSI_ASCQ_WR_UNEXP_UNSOL_DATA 0x0C
+#define SCSI_ASCQ_WR_NOTENG_UNSOL_DATA 0x0D
+
+#define SCSI_ASCQ_LBA_OUT_OF_RANGE 0x00
+#define SCSI_ASCQ_INVALID_ELEMENT_ADDR 0x01
+
+#define SCSI_ASCQ_LUN_WRITE_PROTECTED 0x00
+#define SCSI_ASCQ_LUN_HW_WRITE_PROTECTED 0x01
+#define SCSI_ASCQ_LUN_SW_WRITE_PROTECTED 0x02
+
+#define SCSI_ASCQ_POR 0x01 /* power on reset */
+#define SCSI_ASCQ_SBR 0x02 /* scsi bus reset */
+#define SCSI_ASCQ_BDR 0x03 /* bus device reset */
+#define SCSI_ASCQ_DIR 0x04 /* device internal reset */
+
+#define SCSI_ASCQ_MODE_PARAMS_CHANGED 0x01
+#define SCSI_ASCQ_LOG_PARAMS_CHANGED 0x02
+#define SCSI_ASCQ_RESERVATIONS_PREEMPTED 0x03
+#define SCSI_ASCQ_RESERVATIONS_RELEASED 0x04
+#define SCSI_ASCQ_REGISTRATIONS_PREEMPTED 0x05
+
+#define SCSI_ASCQ_MICROCODE_CHANGED 0x01
+#define SCSI_ASCQ_CHANGED_OPER_COND 0x02
+#define SCSI_ASCQ_INQ_CHANGED 0x03 /* inquiry data changed */
+#define SCSI_ASCQ_DI_CHANGED 0x05 /* device id changed */
+#define SCSI_ASCQ_RL_DATA_CHANGED 0x0E /* report luns data changed */
+
+#define SCSI_ASCQ_DP_CRC_ERR 0x01 /* data phase crc error */
+#define SCSI_ASCQ_DP_SCSI_PARITY_ERR 0x02 /* data phase scsi parity error
+ */
+#define SCSI_ASCQ_IU_CRC_ERR 0x03 /* information unit crc error */
+#define SCSI_ASCQ_PROTO_SERV_CRC_ERR 0x05
+
+#define SCSI_ASCQ_LUN_TIME_OUT 0x01
+
+/* ------------------------------------------------------------
+ * SCSI INQUIRY
+ * ------------------------------------------------------------*/
+
+struct scsi_inquiry_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 reserved1:3;
+ u8 cmd_dt:1;
+ u8 evpd:1;
+#else
+ u8 evpd:1;
+ u8 cmd_dt:1;
+ u8 reserved1:3;
+ u8 lun:3;
+#endif
+ u8 page_code;
+ u8 reserved2;
+ u8 alloc_length;
+ u8 control;
+};
+
+struct scsi_inquiry_vendor_s{
+ u8 vendor_id[8];
+};
+
+struct scsi_inquiry_prodid_s{
+ u8 product_id[16];
+};
+
+struct scsi_inquiry_prodrev_s{
+ u8 product_rev[4];
+};
+
+struct scsi_inquiry_data_s{
+#ifdef __BIGENDIAN
+ u8 peripheral_qual:3; /* peripheral qualifier */
+ u8 device_type:5; /* peripheral device type */
+
+ u8 rmb:1; /* removable medium bit */
+ u8 device_type_mod:7; /* device type modifier */
+
+ u8 version;
+
+ u8 aenc:1; /* async event notification capability
+ */
+ u8 trm_iop:1; /* terminate I/O process */
+ u8 norm_aca:1; /* normal ACA supported */
+ u8 hi_support:1; /* SCSI-3: supports REPORT LUNS */
+ u8 rsp_data_format:4;
+
+ u8 additional_len;
+ u8 sccs:1;
+ u8 reserved1:7;
+
+ u8 reserved2:1;
+ u8 enc_serv:1; /* enclosure service component */
+ u8 reserved3:1;
+ u8 multi_port:1; /* multi-port device */
+ u8 m_chngr:1; /* device in medium transport element */
+ u8 ack_req_q:1; /* SIP specific bit */
+ u8 addr32:1; /* SIP specific bit */
+ u8 addr16:1; /* SIP specific bit */
+
+ u8 rel_adr:1; /* relative address */
+ u8 w_bus32:1;
+ u8 w_bus16:1;
+ u8 synchronous:1;
+ u8 linked_commands:1;
+ u8 trans_dis:1;
+ u8 cmd_queue:1; /* command queueing supported */
+ u8 soft_reset:1; /* soft reset alternative (VS) */
+#else
+ u8 device_type:5; /* peripheral device type */
+ u8 peripheral_qual:3;
+ /* peripheral qualifier */
+
+ u8 device_type_mod:7;
+ /* device type modifier */
+ u8 rmb:1; /* removable medium bit */
+
+ u8 version;
+
+ u8 rsp_data_format:4;
+ u8 hi_support:1; /* SCSI-3: supports REPORT LUNS */
+ u8 norm_aca:1; /* normal ACA supported */
+ u8 terminate_iop:1;/* terminate I/O process */
+ u8 aenc:1; /* async event notification capability
+ */
+
+ u8 additional_len;
+ u8 reserved1:7;
+ u8 sccs:1;
+
+ u8 addr16:1; /* SIP specific bit */
+ u8 addr32:1; /* SIP specific bit */
+ u8 ack_req_q:1; /* SIP specific bit */
+ u8 m_chngr:1; /* device in medium transport element */
+ u8 multi_port:1; /* multi-port device */
+ u8 reserved3:1; /* TBD - Vendor Specific */
+ u8 enc_serv:1; /* enclosure service component */
+ u8 reserved2:1;
+
+ u8 soft_seset:1; /* soft reset alternative (VS) */
+ u8 cmd_queue:1; /* command queueing supported */
+ u8 trans_dis:1;
+ u8 linked_commands:1;
+ u8 synchronous:1;
+ u8 w_bus16:1;
+ u8 w_bus32:1;
+ u8 rel_adr:1; /* relative address */
+#endif
+ struct scsi_inquiry_vendor_s vendor_id;
+ struct scsi_inquiry_prodid_s product_id;
+ struct scsi_inquiry_prodrev_s product_rev;
+ u8 vendor_specific[20];
+ u8 reserved4[40];
+};
+
+/*
+ * inquiry.peripheral_qual field values
+ */
+#define SCSI_DEVQUAL_DEFAULT 0
+#define SCSI_DEVQUAL_NOT_CONNECTED 1
+#define SCSI_DEVQUAL_NOT_SUPPORTED 3
+
+/*
+ * inquiry.device_type field values
+ */
+#define SCSI_DEVICE_DIRECT_ACCESS 0x00
+#define SCSI_DEVICE_SEQ_ACCESS 0x01
+#define SCSI_DEVICE_ARRAY_CONTROLLER 0x0C
+#define SCSI_DEVICE_UNKNOWN 0x1F
+
+/*
+ * inquiry.version
+ */
+#define SCSI_VERSION_ANSI_X3131 2 /* ANSI X3.131 SCSI-2 */
+#define SCSI_VERSION_SPC 3 /* SPC (SCSI-3), ANSI X3.301:1997 */
+#define SCSI_VERSION_SPC_2 4 /* SPC-2 */
+
+/*
+ * response data format
+ */
+#define SCSI_RSP_DATA_FORMAT 2 /* SCSI-2 & SPC */
+
+/*
+ * SCSI inquiry page codes
+ */
+#define SCSI_INQ_PAGE_VPD_PAGES 0x00 /* supported vpd pages */
+#define SCSI_INQ_PAGE_USN_PAGE 0x80 /* unit serial number page */
+#define SCSI_INQ_PAGE_DEV_IDENT 0x83 /* device indentification page
+ */
+#define SCSI_INQ_PAGES_MAX 3
+
+/*
+ * supported vital product data pages
+ */
+struct scsi_inq_page_vpd_pages_s{
+#ifdef __BIGENDIAN
+ u8 peripheral_qual:3;
+ u8 device_type:5;
+#else
+ u8 device_type:5;
+ u8 peripheral_qual:3;
+#endif
+ u8 page_code;
+ u8 reserved;
+ u8 page_length;
+ u8 pages[SCSI_INQ_PAGES_MAX];
+};
+
+/*
+ * Unit serial number page
+ */
+#define SCSI_INQ_USN_LEN 32
+
+struct scsi_inq_usn_s{
+ char usn[SCSI_INQ_USN_LEN];
+};
+
+struct scsi_inq_page_usn_s{
+#ifdef __BIGENDIAN
+ u8 peripheral_qual:3;
+ u8 device_type:5;
+#else
+ u8 device_type:5;
+ u8 peripheral_qual:3;
+#endif
+ u8 page_code;
+ u8 reserved1;
+ u8 page_length;
+ struct scsi_inq_usn_s usn;
+};
+
+enum {
+ SCSI_INQ_DIP_CODE_BINARY = 1, /* identifier has binary value */
+ SCSI_INQ_DIP_CODE_ASCII = 2, /* identifier has ascii value */
+};
+
+enum {
+ SCSI_INQ_DIP_ASSOC_LUN = 0, /* id is associated with device */
+ SCSI_INQ_DIP_ASSOC_PORT = 1, /* id is associated with port that
+ * received the request
+ */
+};
+
+enum {
+ SCSI_INQ_ID_TYPE_VENDOR = 1,
+ SCSI_INQ_ID_TYPE_IEEE = 2,
+ SCSI_INQ_ID_TYPE_FC_FS = 3,
+ SCSI_INQ_ID_TYPE_OTHER = 4,
+};
+
+struct scsi_inq_dip_desc_s{
+#ifdef __BIGENDIAN
+ u8 res0:4;
+ u8 code_set:4;
+ u8 res1:2;
+ u8 association:2;
+ u8 id_type:4;
+#else
+ u8 code_set:4;
+ u8 res0:4;
+ u8 id_type:4;
+ u8 association:2;
+ u8 res1:2;
+#endif
+ u8 res2;
+ u8 id_len;
+ struct scsi_lun_sn_s id;
+};
+
+/*
+ * Device indentification page
+ */
+struct scsi_inq_page_dev_ident_s{
+#ifdef __BIGENDIAN
+ u8 peripheral_qual:3;
+ u8 device_type:5;
+#else
+ u8 device_type:5;
+ u8 peripheral_qual:3;
+#endif
+ u8 page_code;
+ u8 reserved1;
+ u8 page_length;
+ struct scsi_inq_dip_desc_s desc;
+};
+
+/* ------------------------------------------------------------
+ * READ CAPACITY
+ * ------------------------------------------------------------
+ */
+
+struct scsi_read_capacity_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 reserved1:4;
+ u8 rel_adr:1;
+#else
+ u8 rel_adr:1;
+ u8 reserved1:4;
+ u8 lun:3;
+#endif
+ u8 lba0; /* MSB */
+ u8 lba1;
+ u8 lba2;
+ u8 lba3; /* LSB */
+ u8 reserved2;
+ u8 reserved3;
+#ifdef __BIGENDIAN
+ u8 reserved4:7;
+ u8 pmi:1; /* partial medium indicator */
+#else
+ u8 pmi:1; /* partial medium indicator */
+ u8 reserved4:7;
+#endif
+ u8 control;
+};
+
+struct scsi_read_capacity_data_s{
+ u32 max_lba; /* maximum LBA available */
+ u32 block_length; /* in bytes */
+};
+
+struct scsi_read_capacity16_data_s{
+ u64 lba; /* maximum LBA available */
+ u32 block_length; /* in bytes */
+#ifdef __BIGENDIAN
+ u8 reserved1:4,
+ p_type:3,
+ prot_en:1;
+ u8 reserved2:4,
+ lb_pbe:4; /* logical blocks per physical block
+ * exponent */
+ u16 reserved3:2,
+ lba_align:14; /* lowest aligned logical block
+ * address */
+#else
+ u16 lba_align:14, /* lowest aligned logical block
+ * address */
+ reserved3:2;
+ u8 lb_pbe:4, /* logical blocks per physical block
+ * exponent */
+ reserved2:4;
+ u8 prot_en:1,
+ p_type:3,
+ reserved1:4;
+#endif
+ u64 reserved4;
+ u64 reserved5;
+};
+
+/* ------------------------------------------------------------
+ * REPORT LUNS command
+ * ------------------------------------------------------------
+ */
+
+struct scsi_report_luns_s{
+ u8 opcode; /* A0h - REPORT LUNS opCode */
+ u8 reserved1[5];
+ u8 alloc_length[4];/* allocation length MSB first */
+ u8 reserved2;
+ u8 control;
+};
+
+#define SCSI_REPORT_LUN_ALLOC_LENGTH(rl) \
+ ((rl->alloc_length[0] << 24) | (rl->alloc_length[1] << 16) | \
+ (rl->alloc_length[2] << 8) | (rl->alloc_length[3]))
+
+#define SCSI_REPORT_LUNS_SET_ALLOCLEN(rl, alloc_len) { \
+ (rl)->alloc_length[0] = (alloc_len) >> 24; \
+ (rl)->alloc_length[1] = ((alloc_len) >> 16) & 0xFF; \
+ (rl)->alloc_length[2] = ((alloc_len) >> 8) & 0xFF; \
+ (rl)->alloc_length[3] = (alloc_len) & 0xFF; \
+}
+
+struct scsi_report_luns_data_s{
+ u32 lun_list_length; /* length of LUN list length */
+ u32 reserved;
+ lun_t lun[1]; /* first LUN in lun list */
+};
+
+/* -------------------------------------------------------------
+ * SCSI mode parameters
+ * -----------------------------------------------------------
+ */
+enum {
+ SCSI_DA_MEDIUM_DEF = 0, /* direct access default medium type */
+ SCSI_DA_MEDIUM_SS = 1, /* direct access single sided */
+ SCSI_DA_MEDIUM_DS = 2, /* direct access double sided */
+};
+
+/*
+ * SCSI Mode Select(6) cdb
+ */
+struct scsi_mode_select6_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 pf:1; /* page format */
+ u8 reserved2:3;
+ u8 sp:1; /* save pages if set to 1 */
+#else
+ u8 sp:1; /* save pages if set to 1 */
+ u8 reserved2:3;
+ u8 pf:1; /* page format */
+ u8 reserved1:3;
+#endif
+ u8 reserved3[2];
+ u8 alloc_len;
+ u8 control;
+};
+
+/*
+ * SCSI Mode Select(10) cdb
+ */
+struct scsi_mode_select10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 pf:1; /* page format */
+ u8 reserved2:3;
+ u8 sp:1; /* save pages if set to 1 */
+#else
+ u8 sp:1; /* save pages if set to 1 */
+ u8 reserved2:3;
+ u8 pf:1; /* page format */
+ u8 reserved1:3;
+#endif
+ u8 reserved3[5];
+ u8 alloc_len_msb;
+ u8 alloc_len_lsb;
+ u8 control;
+};
+
+/*
+ * SCSI Mode Sense(6) cdb
+ */
+struct scsi_mode_sense6_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:4;
+ u8 dbd:1; /* disable block discriptors if set to 1 */
+ u8 reserved2:3;
+
+ u8 pc:2; /* page control */
+ u8 page_code:6;
+#else
+ u8 reserved2:3;
+ u8 dbd:1; /* disable block descriptors if set to 1 */
+ u8 reserved1:4;
+
+ u8 page_code:6;
+ u8 pc:2; /* page control */
+#endif
+ u8 reserved3;
+ u8 alloc_len;
+ u8 control;
+};
+
+/*
+ * SCSI Mode Sense(10) cdb
+ */
+struct scsi_mode_sense10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 LLBAA:1; /* long LBA accepted if set to 1 */
+ u8 dbd:1; /* disable block descriptors if set
+ * to 1
+ */
+ u8 reserved2:3;
+
+ u8 pc:2; /* page control */
+ u8 page_code:6;
+#else
+ u8 reserved2:3;
+ u8 dbd:1; /* disable block descriptors if set to
+ * 1
+ */
+ u8 LLBAA:1; /* long LBA accepted if set to 1 */
+ u8 reserved1:3;
+
+ u8 page_code:6;
+ u8 pc:2; /* page control */
+#endif
+ u8 reserved3[4];
+ u8 alloc_len_msb;
+ u8 alloc_len_lsb;
+ u8 control;
+};
+
+#define SCSI_CDB10_GET_AL(cdb) \
+ ((cdb)->alloc_len_msb << 8 | (cdb)->alloc_len_lsb)
+
+#define SCSI_CDB10_SET_AL(cdb, al) { \
+ (cdb)->alloc_len_msb = al >> 8; \
+ (cdb)->alloc_len_lsb = al & 0xFF; \
+}
+
+#define SCSI_CDB6_GET_AL(cdb) ((cdb)->alloc_len)
+
+#define SCSI_CDB6_SET_AL(cdb, al) { \
+ (cdb)->alloc_len = al; \
+}
+
+/*
+ * page control field values
+ */
+#define SCSI_PC_CURRENT_VALUES 0x0
+#define SCSI_PC_CHANGEABLE_VALUES 0x1
+#define SCSI_PC_DEFAULT_VALUES 0x2
+#define SCSI_PC_SAVED_VALUES 0x3
+
+/*
+ * SCSI mode page codes
+ */
+#define SCSI_MP_VENDOR_SPEC 0x00
+#define SCSI_MP_DISC_RECN 0x02 /* disconnect-reconnect page */
+#define SCSI_MP_FORMAT_DEVICE 0x03
+#define SCSI_MP_RDG 0x04 /* rigid disk geometry page */
+#define SCSI_MP_FDP 0x05 /* flexible disk page */
+#define SCSI_MP_CACHING 0x08 /* caching page */
+#define SCSI_MP_CONTROL 0x0A /* control mode page */
+#define SCSI_MP_MED_TYPES_SUP 0x0B /* medium types supported page */
+#define SCSI_MP_INFO_EXCP_CNTL 0x1C /* informational exception control */
+#define SCSI_MP_ALL 0x3F /* return all pages - mode sense only */
+
+/*
+ * mode parameter header
+ */
+struct scsi_mode_param_header6_s{
+ u8 mode_datalen;
+ u8 medium_type;
+
+ /*
+ * device specific parameters expanded for direct access devices
+ */
+#ifdef __BIGENDIAN
+ u32 wp:1; /* write protected */
+ u32 reserved1:2;
+ u32 dpofua:1; /* disable page out + force unit access
+ */
+ u32 reserved2:4;
+#else
+ u32 reserved2:4;
+ u32 dpofua:1; /* disable page out + force unit access
+ */
+ u32 reserved1:2;
+ u32 wp:1; /* write protected */
+#endif
+
+ u8 block_desclen;
+};
+
+struct scsi_mode_param_header10_s{
+ u32 mode_datalen:16;
+ u32 medium_type:8;
+
+ /*
+ * device specific parameters expanded for direct access devices
+ */
+#ifdef __BIGENDIAN
+ u32 wp:1; /* write protected */
+ u32 reserved1:2;
+ u32 dpofua:1; /* disable page out + force unit access
+ */
+ u32 reserved2:4;
+#else
+ u32 reserved2:4;
+ u32 dpofua:1; /* disable page out + force unit access
+ */
+ u32 reserved1:2;
+ u32 wp:1; /* write protected */
+#endif
+
+#ifdef __BIGENDIAN
+ u32 reserved3:7;
+ u32 longlba:1;
+#else
+ u32 longlba:1;
+ u32 reserved3:7;
+#endif
+ u32 reserved4:8;
+ u32 block_desclen:16;
+};
+
+/*
+ * mode parameter block descriptor
+ */
+struct scsi_mode_param_desc_s{
+ u32 nblks;
+ u32 density_code:8;
+ u32 block_length:24;
+};
+
+/*
+ * Disconnect-reconnect mode page format
+ */
+struct scsi_mp_disc_recn_s{
+#ifdef __BIGENDIAN
+ u8 ps:1;
+ u8 reserved1:1;
+ u8 page_code:6;
+#else
+ u8 page_code:6;
+ u8 reserved1:1;
+ u8 ps:1;
+#endif
+ u8 page_len;
+ u8 buf_full_ratio;
+ u8 buf_empty_ratio;
+
+ u8 bil_msb; /* bus inactivity limit -MSB */
+ u8 bil_lsb; /* bus inactivity limit -LSB */
+
+ u8 dtl_msb; /* disconnect time limit - MSB */
+ u8 dtl_lsb; /* disconnect time limit - LSB */
+
+ u8 ctl_msb; /* connect time limit - MSB */
+ u8 ctl_lsb; /* connect time limit - LSB */
+
+ u8 max_burst_len_msb;
+ u8 max_burst_len_lsb;
+#ifdef __BIGENDIAN
+ u8 emdp:1; /* enable modify data pointers */
+ u8 fa:3; /* fair arbitration */
+ u8 dimm:1; /* disconnect immediate */
+ u8 dtdc:3; /* data transfer disconnect control */
+#else
+ u8 dtdc:3; /* data transfer disconnect control */
+ u8 dimm:1; /* disconnect immediate */
+ u8 fa:3; /* fair arbitration */
+ u8 emdp:1; /* enable modify data pointers */
+#endif
+
+ u8 reserved3;
+
+ u8 first_burst_len_msb;
+ u8 first_burst_len_lsb;
+};
+
+/*
+ * SCSI format device mode page
+ */
+struct scsi_mp_format_device_s{
+#ifdef __BIGENDIAN
+ u32 ps:1;
+ u32 reserved1:1;
+ u32 page_code:6;
+#else
+ u32 page_code:6;
+ u32 reserved1:1;
+ u32 ps:1;
+#endif
+ u32 page_len:8;
+ u32 tracks_per_zone:16;
+
+ u32 a_sec_per_zone:16;
+ u32 a_tracks_per_zone:16;
+
+ u32 a_tracks_per_lun:16; /* alternate tracks/lun-MSB */
+ u32 sec_per_track:16; /* sectors/track-MSB */
+
+ u32 bytes_per_sector:16;
+ u32 interleave:16;
+
+ u32 tsf:16; /* track skew factor-MSB */
+ u32 csf:16; /* cylinder skew factor-MSB */
+
+#ifdef __BIGENDIAN
+ u32 ssec:1; /* soft sector formatting */
+ u32 hsec:1; /* hard sector formatting */
+ u32 rmb:1; /* removable media */
+ u32 surf:1; /* surface */
+ u32 reserved2:4;
+#else
+ u32 reserved2:4;
+ u32 surf:1; /* surface */
+ u32 rmb:1; /* removable media */
+ u32 hsec:1; /* hard sector formatting */
+ u32 ssec:1; /* soft sector formatting */
+#endif
+ u32 reserved3:24;
+};
+
+/*
+ * SCSI rigid disk device geometry page
+ */
+struct scsi_mp_rigid_device_geometry_s{
+#ifdef __BIGENDIAN
+ u32 ps:1;
+ u32 reserved1:1;
+ u32 page_code:6;
+#else
+ u32 page_code:6;
+ u32 reserved1:1;
+ u32 ps:1;
+#endif
+ u32 page_len:8;
+ u32 num_cylinders0:8;
+ u32 num_cylinders1:8;
+
+ u32 num_cylinders2:8;
+ u32 num_heads:8;
+ u32 scwp0:8;
+ u32 scwp1:8;
+
+ u32 scwp2:8;
+ u32 scrwc0:8;
+ u32 scrwc1:8;
+ u32 scrwc2:8;
+
+ u32 dsr:16;
+ u32 lscyl0:8;
+ u32 lscyl1:8;
+
+ u32 lscyl2:8;
+#ifdef __BIGENDIAN
+ u32 reserved2:6;
+ u32 rpl:2; /* rotational position locking */
+#else
+ u32 rpl:2; /* rotational position locking */
+ u32 reserved2:6;
+#endif
+ u32 rot_off:8;
+ u32 reserved3:8;
+
+ u32 med_rot_rate:16;
+ u32 reserved4:16;
+};
+
+/*
+ * SCSI caching mode page
+ */
+struct scsi_mp_caching_s{
+#ifdef __BIGENDIAN
+ u8 ps:1;
+ u8 res1:1;
+ u8 page_code:6;
+#else
+ u8 page_code:6;
+ u8 res1:1;
+ u8 ps:1;
+#endif
+ u8 page_len;
+#ifdef __BIGENDIAN
+ u8 ic:1; /* initiator control */
+ u8 abpf:1; /* abort pre-fetch */
+ u8 cap:1; /* caching analysis permitted */
+ u8 disc:1; /* discontinuity */
+ u8 size:1; /* size enable */
+ u8 wce:1; /* write cache enable */
+ u8 mf:1; /* multiplication factor */
+ u8 rcd:1; /* read cache disable */
+
+ u8 drrp:4; /* demand read retention priority */
+ u8 wrp:4; /* write retention priority */
+#else
+ u8 rcd:1; /* read cache disable */
+ u8 mf:1; /* multiplication factor */
+ u8 wce:1; /* write cache enable */
+ u8 size:1; /* size enable */
+ u8 disc:1; /* discontinuity */
+ u8 cap:1; /* caching analysis permitted */
+ u8 abpf:1; /* abort pre-fetch */
+ u8 ic:1; /* initiator control */
+
+ u8 wrp:4; /* write retention priority */
+ u8 drrp:4; /* demand read retention priority */
+#endif
+ u8 dptl[2];/* disable pre-fetch transfer length */
+ u8 min_prefetch[2];
+ u8 max_prefetch[2];
+ u8 max_prefetch_limit[2];
+#ifdef __BIGENDIAN
+ u8 fsw:1; /* force sequential write */
+ u8 lbcss:1;/* logical block cache segment size */
+ u8 dra:1; /* disable read ahead */
+ u8 vs:2; /* vendor specific */
+ u8 res2:3;
+#else
+ u8 res2:3;
+ u8 vs:2; /* vendor specific */
+ u8 dra:1; /* disable read ahead */
+ u8 lbcss:1;/* logical block cache segment size */
+ u8 fsw:1; /* force sequential write */
+#endif
+ u8 num_cache_segs;
+
+ u8 cache_seg_size[2];
+ u8 res3;
+ u8 non_cache_seg_size[3];
+};
+
+/*
+ * SCSI control mode page
+ */
+struct scsi_mp_control_page_s{
+#ifdef __BIGENDIAN
+u8 ps:1;
+u8 reserved1:1;
+u8 page_code:6;
+#else
+u8 page_code:6;
+u8 reserved1:1;
+u8 ps:1;
+#endif
+ u8 page_len;
+#ifdef __BIGENDIAN
+ u8 tst:3; /* task set type */
+ u8 reserved3:3;
+ u8 gltsd:1; /* global logging target save disable */
+ u8 rlec:1; /* report log exception condition */
+
+ u8 qalgo_mod:4; /* queue alogorithm modifier */
+ u8 reserved4:1;
+ u8 qerr:2; /* queue error management */
+ u8 dque:1; /* disable queuing */
+
+ u8 reserved5:1;
+ u8 rac:1; /* report a check */
+ u8 reserved6:2;
+ u8 swp:1; /* software write protect */
+ u8 raerp:1; /* ready AER permission */
+ u8 uaaerp:1; /* unit attenstion AER permission */
+ u8 eaerp:1; /* error AER permission */
+
+ u8 reserved7:5;
+ u8 autoload_mod:3;
+#else
+ u8 rlec:1; /* report log exception condition */
+ u8 gltsd:1; /* global logging target save disable */
+ u8 reserved3:3;
+ u8 tst:3; /* task set type */
+
+ u8 dque:1; /* disable queuing */
+ u8 qerr:2; /* queue error management */
+ u8 reserved4:1;
+ u8 qalgo_mod:4; /* queue alogorithm modifier */
+
+ u8 eaerp:1; /* error AER permission */
+ u8 uaaerp:1; /* unit attenstion AER permission */
+ u8 raerp:1; /* ready AER permission */
+ u8 swp:1; /* software write protect */
+ u8 reserved6:2;
+ u8 rac:1; /* report a check */
+ u8 reserved5:1;
+
+ u8 autoload_mod:3;
+ u8 reserved7:5;
+#endif
+ u8 rahp_msb; /* ready AER holdoff period - MSB */
+ u8 rahp_lsb; /* ready AER holdoff period - LSB */
+
+ u8 busy_timeout_period_msb;
+ u8 busy_timeout_period_lsb;
+
+ u8 ext_selftest_compl_time_msb;
+ u8 ext_selftest_compl_time_lsb;
+};
+
+/*
+ * SCSI medium types supported mode page
+ */
+struct scsi_mp_medium_types_sup_s{
+#ifdef __BIGENDIAN
+ u8 ps:1;
+ u8 reserved1:1;
+ u8 page_code:6;
+#else
+ u8 page_code:6;
+ u8 reserved1:1;
+ u8 ps:1;
+#endif
+ u8 page_len;
+
+ u8 reserved3[2];
+ u8 med_type1_sup; /* medium type one supported */
+ u8 med_type2_sup; /* medium type two supported */
+ u8 med_type3_sup; /* medium type three supported */
+ u8 med_type4_sup; /* medium type four supported */
+};
+
+/*
+ * SCSI informational exception control mode page
+ */
+struct scsi_mp_info_excpt_cntl_s{
+#ifdef __BIGENDIAN
+ u8 ps:1;
+ u8 reserved1:1;
+ u8 page_code:6;
+#else
+ u8 page_code:6;
+ u8 reserved1:1;
+ u8 ps:1;
+#endif
+ u8 page_len;
+#ifdef __BIGENDIAN
+ u8 perf:1; /* performance */
+ u8 reserved3:1;
+ u8 ebf:1; /* enable background fucntion */
+ u8 ewasc:1; /* enable warning */
+ u8 dexcpt:1; /* disable exception control */
+ u8 test:1; /* enable test device failure
+ * notification
+ */
+ u8 reserved4:1;
+ u8 log_error:1;
+
+ u8 reserved5:4;
+ u8 mrie:4; /* method of reporting info
+ * exceptions
+ */
+#else
+ u8 log_error:1;
+ u8 reserved4:1;
+ u8 test:1; /* enable test device failure
+ * notification
+ */
+ u8 dexcpt:1; /* disable exception control */
+ u8 ewasc:1; /* enable warning */
+ u8 ebf:1; /* enable background fucntion */
+ u8 reserved3:1;
+ u8 perf:1; /* performance */
+
+ u8 mrie:4; /* method of reporting info
+ * exceptions
+ */
+ u8 reserved5:4;
+#endif
+ u8 interval_timer_msb;
+ u8 interval_timer_lsb;
+
+ u8 report_count_msb;
+ u8 report_count_lsb;
+};
+
+/*
+ * Methods of reporting informational exceptions
+ */
+#define SCSI_MP_IEC_NO_REPORT 0x0 /* no reporting of exceptions */
+#define SCSI_MP_IEC_AER 0x1 /* async event reporting */
+#define SCSI_MP_IEC_UNIT_ATTN 0x2 /* generate unit attenstion */
+#define SCSI_MO_IEC_COND_REC_ERR 0x3 /* conditionally generate recovered
+ * error
+ */
+#define SCSI_MP_IEC_UNCOND_REC_ERR 0x4 /* unconditionally generate recovered
+ * error
+ */
+#define SCSI_MP_IEC_NO_SENSE 0x5 /* generate no sense */
+#define SCSI_MP_IEC_ON_REQUEST 0x6 /* only report exceptions on request */
+
+/*
+ * SCSI flexible disk page
+ */
+struct scsi_mp_flexible_disk_s{
+#ifdef __BIGENDIAN
+ u8 ps:1;
+ u8 reserved1:1;
+ u8 page_code:6;
+#else
+ u8 page_code:6;
+ u8 reserved1:1;
+ u8 ps:1;
+#endif
+ u8 page_len;
+
+ u8 transfer_rate_msb;
+ u8 transfer_rate_lsb;
+
+ u8 num_heads;
+ u8 num_sectors;
+
+ u8 bytes_per_sector_msb;
+ u8 bytes_per_sector_lsb;
+
+ u8 num_cylinders_msb;
+ u8 num_cylinders_lsb;
+
+ u8 sc_wpc_msb; /* starting cylinder-write
+ * precompensation msb
+ */
+ u8 sc_wpc_lsb; /* starting cylinder-write
+ * precompensation lsb
+ */
+ u8 sc_rwc_msb; /* starting cylinder-reduced write
+ * current msb
+ */
+ u8 sc_rwc_lsb; /* starting cylinder-reduced write
+ * current lsb
+ */
+
+ u8 dev_step_rate_msb;
+ u8 dev_step_rate_lsb;
+
+ u8 dev_step_pulse_width;
+
+ u8 head_sd_msb; /* head settle delay msb */
+ u8 head_sd_lsb; /* head settle delay lsb */
+
+ u8 motor_on_delay;
+ u8 motor_off_delay;
+#ifdef __BIGENDIAN
+ u8 trdy:1; /* true ready bit */
+ u8 ssn:1; /* start sector number bit */
+ u8 mo:1; /* motor on bit */
+ u8 reserved3:5;
+
+ u8 reserved4:4;
+ u8 spc:4; /* step pulse per cylinder */
+#else
+ u8 reserved3:5;
+ u8 mo:1; /* motor on bit */
+ u8 ssn:1; /* start sector number bit */
+ u8 trdy:1; /* true ready bit */
+
+ u8 spc:4; /* step pulse per cylinder */
+ u8 reserved4:4;
+#endif
+ u8 write_comp;
+ u8 head_load_delay;
+ u8 head_unload_delay;
+#ifdef __BIGENDIAN
+ u8 pin34:4; /* pin34 usage */
+ u8 pin2:4; /* pin2 usage */
+
+ u8 pin4:4; /* pin4 usage */
+ u8 pin1:4; /* pin1 usage */
+#else
+ u8 pin2:4; /* pin2 usage */
+ u8 pin34:4; /* pin34 usage */
+
+ u8 pin1:4; /* pin1 usage */
+ u8 pin4:4; /* pin4 usage */
+#endif
+ u8 med_rot_rate_msb;
+ u8 med_rot_rate_lsb;
+
+ u8 reserved5[2];
+};
+
+struct scsi_mode_page_format_data6_s{
+ struct scsi_mode_param_header6_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_format_device_s format; /* format device data */
+};
+
+struct scsi_mode_page_format_data10_s{
+ struct scsi_mode_param_header10_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_format_device_s format; /* format device data */
+};
+
+struct scsi_mode_page_rdg_data6_s{
+ struct scsi_mode_param_header6_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_rigid_device_geometry_s rdg;
+ /* rigid geometry data */
+};
+
+struct scsi_mode_page_rdg_data10_s{
+ struct scsi_mode_param_header10_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_rigid_device_geometry_s rdg;
+ /* rigid geometry data */
+};
+
+struct scsi_mode_page_cache6_s{
+ struct scsi_mode_param_header6_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_caching_s cache; /* cache page data */
+};
+
+struct scsi_mode_page_cache10_s{
+ struct scsi_mode_param_header10_s mph; /* mode page header */
+ struct scsi_mode_param_desc_s desc; /* block descriptor */
+ struct scsi_mp_caching_s cache; /* cache page data */
+};
+
+/* --------------------------------------------------------------
+ * Format Unit command
+ * ------------------------------------------------------------
+ */
+
+/*
+ * Format Unit CDB
+ */
+struct scsi_format_unit_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 res1:3;
+ u8 fmtdata:1; /* if set, data out phase has format
+ * data
+ */
+ u8 cmplst:1; /* if set, defect list is complete */
+ u8 def_list:3; /* format of defect descriptor is
+ * fmtdata =1
+ */
+#else
+ u8 def_list:3; /* format of defect descriptor is
+ * fmtdata = 1
+ */
+ u8 cmplst:1; /* if set, defect list is complete */
+ u8 fmtdata:1; /* if set, data out phase has format
+ * data
+ */
+ u8 res1:3;
+#endif
+ u8 interleave_msb;
+ u8 interleave_lsb;
+ u8 vendor_spec;
+ u8 control;
+};
+
+/*
+ * h
+ */
+struct scsi_reserve6_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved:3;
+ u8 obsolete:4;
+ u8 extent:1;
+#else
+ u8 extent:1;
+ u8 obsolete:4;
+ u8 reserved:3;
+#endif
+ u8 reservation_id;
+ u16 param_list_len;
+ u8 control;
+};
+
+/*
+ * h
+ */
+struct scsi_release6_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 obsolete:4;
+ u8 extent:1;
+#else
+ u8 extent:1;
+ u8 obsolete:4;
+ u8 reserved1:3;
+#endif
+ u8 reservation_id;
+ u16 reserved2;
+ u8 control;
+};
+
+/*
+ * h
+ */
+struct scsi_reserve10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 third_party:1;
+ u8 reserved2:2;
+ u8 long_id:1;
+ u8 extent:1;
+#else
+ u8 extent:1;
+ u8 long_id:1;
+ u8 reserved2:2;
+ u8 third_party:1;
+ u8 reserved1:3;
+#endif
+ u8 reservation_id;
+ u8 third_pty_dev_id;
+ u8 reserved3;
+ u8 reserved4;
+ u8 reserved5;
+ u16 param_list_len;
+ u8 control;
+};
+
+struct scsi_release10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 third_party:1;
+ u8 reserved2:2;
+ u8 long_id:1;
+ u8 extent:1;
+#else
+ u8 extent:1;
+ u8 long_id:1;
+ u8 reserved2:2;
+ u8 third_party:1;
+ u8 reserved1:3;
+#endif
+ u8 reservation_id;
+ u8 third_pty_dev_id;
+ u8 reserved3;
+ u8 reserved4;
+ u8 reserved5;
+ u16 param_list_len;
+ u8 control;
+};
+
+struct scsi_verify10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 dpo:1;
+ u8 reserved:2;
+ u8 bytchk:1;
+ u8 reladdr:1;
+#else
+ u8 reladdr:1;
+ u8 bytchk:1;
+ u8 reserved:2;
+ u8 dpo:1;
+ u8 lun:3;
+#endif
+ u8 lba0;
+ u8 lba1;
+ u8 lba2;
+ u8 lba3;
+ u8 reserved1;
+ u8 verification_len0;
+ u8 verification_len1;
+ u8 control_byte;
+};
+
+struct scsi_request_sense_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 lun:3;
+ u8 reserved:5;
+#else
+ u8 reserved:5;
+ u8 lun:3;
+#endif
+ u8 reserved0;
+ u8 reserved1;
+ u8 alloc_len;
+ u8 control_byte;
+};
+
+/* ------------------------------------------------------------
+ * SCSI status byte values
+ * ------------------------------------------------------------
+ */
+#define SCSI_STATUS_GOOD 0x00
+#define SCSI_STATUS_CHECK_CONDITION 0x02
+#define SCSI_STATUS_CONDITION_MET 0x04
+#define SCSI_STATUS_BUSY 0x08
+#define SCSI_STATUS_INTERMEDIATE 0x10
+#define SCSI_STATUS_ICM 0x14 /* intermediate condition met */
+#define SCSI_STATUS_RESERVATION_CONFLICT 0x18
+#define SCSI_STATUS_COMMAND_TERMINATED 0x22
+#define SCSI_STATUS_QUEUE_FULL 0x28
+#define SCSI_STATUS_ACA_ACTIVE 0x30
+
+#define SCSI_MAX_ALLOC_LEN 0xFF /* maximum allocarion length
+ * in CDBs
+ */
+
+#define SCSI_OP_WRITE_VERIFY10 0x2E
+#define SCSI_OP_WRITE_VERIFY12 0xAE
+#define SCSI_OP_UNDEF 0xFF
+
+/*
+ * SCSI WRITE-VERIFY(10) command
+ */
+struct scsi_write_verify10_s{
+ u8 opcode;
+#ifdef __BIGENDIAN
+ u8 reserved1:3;
+ u8 dpo:1; /* Disable Page Out */
+ u8 reserved2:1;
+ u8 ebp:1; /* erse by-pass */
+ u8 bytchk:1; /* byte check */
+ u8 rel_adr:1; /* relative address */
+#else
+ u8 rel_adr:1; /* relative address */
+ u8 bytchk:1; /* byte check */
+ u8 ebp:1; /* erse by-pass */
+ u8 reserved2:1;
+ u8 dpo:1; /* Disable Page Out */
+ u8 reserved1:3;
+#endif
+ u8 lba0; /* logical block address - MSB */
+ u8 lba1;
+ u8 lba2;
+ u8 lba3; /* LSB */
+ u8 reserved3;
+ u8 xfer_length0; /* transfer length in blocks - MSB */
+ u8 xfer_length1; /* LSB */
+ u8 control;
+};
+
+#pragma pack()
+
+#endif /* __SCSI_H__ */
diff --git a/drivers/scsi/bfa/include/protocol/types.h b/drivers/scsi/bfa/include/protocol/types.h
new file mode 100644
index 000000000000..2875a6cced3b
--- /dev/null
+++ b/drivers/scsi/bfa/include/protocol/types.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * types.h Protocol defined base types
+ */
+
+#ifndef __TYPES_H__
+#define __TYPES_H__
+
+#include <bfa_os_inc.h>
+
+#define wwn_t u64
+#define lun_t u64
+
+#define WWN_NULL (0)
+#define FC_SYMNAME_MAX 256 /* max name server symbolic name size */
+#define FC_ALPA_MAX 128
+
+#pragma pack(1)
+
+#define MAC_ADDRLEN (6)
+struct mac_s { u8 mac[MAC_ADDRLEN]; };
+#define mac_t struct mac_s
+
+#pragma pack()
+
+#endif
diff --git a/drivers/scsi/bfa/loop.c b/drivers/scsi/bfa/loop.c
new file mode 100644
index 000000000000..f7c7f4f3c640
--- /dev/null
+++ b/drivers/scsi/bfa/loop.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * port_loop.c vport private loop implementation.
+ */
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_trcmod.h"
+#include "lport_priv.h"
+
+BFA_TRC_FILE(FCS, LOOP);
+
+/**
+ * ALPA to LIXA bitmap mapping
+ *
+ * ALPA 0x00 (Word 0, Bit 30) is invalid for N_Ports. Also Word 0 Bit 31
+ * is for L_bit (login required) and is filled as ALPA 0x00 here.
+ */
+static const u8 port_loop_alpa_map[] = {
+ 0xEF, 0xE8, 0xE4, 0xE2, 0xE1, 0xE0, 0xDC, 0xDA, /* Word 3 Bits 0..7 */
+ 0xD9, 0xD6, 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xCE, /* Word 3 Bits 8..15 */
+ 0xCD, 0xCC, 0xCB, 0xCA, 0xC9, 0xC7, 0xC6, 0xC5, /* Word 3 Bits 16..23 */
+ 0xC3, 0xBC, 0xBA, 0xB9, 0xB6, 0xB5, 0xB4, 0xB3, /* Word 3 Bits 24..31 */
+
+ 0xB2, 0xB1, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, /* Word 2 Bits 0..7 */
+ 0xA7, 0xA6, 0xA5, 0xA3, 0x9F, 0x9E, 0x9D, 0x9B, /* Word 2 Bits 8..15 */
+ 0x98, 0x97, 0x90, 0x8F, 0x88, 0x84, 0x82, 0x81, /* Word 2 Bits 16..23 */
+ 0x80, 0x7C, 0x7A, 0x79, 0x76, 0x75, 0x74, 0x73, /* Word 2 Bits 24..31 */
+
+ 0x72, 0x71, 0x6E, 0x6D, 0x6C, 0x6B, 0x6A, 0x69, /* Word 1 Bits 0..7 */
+ 0x67, 0x66, 0x65, 0x63, 0x5C, 0x5A, 0x59, 0x56, /* Word 1 Bits 8..15 */
+ 0x55, 0x54, 0x53, 0x52, 0x51, 0x4E, 0x4D, 0x4C, /* Word 1 Bits 16..23 */
+ 0x4B, 0x4A, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3C, /* Word 1 Bits 24..31 */
+
+ 0x3A, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, /* Word 0 Bits 0..7 */
+ 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, 0x27, 0x26, /* Word 0 Bits 8..15 */
+ 0x25, 0x23, 0x1F, 0x1E, 0x1D, 0x1B, 0x18, 0x17, /* Word 0 Bits 16..23 */
+ 0x10, 0x0F, 0x08, 0x04, 0x02, 0x01, 0x00, 0x00, /* Word 0 Bits 24..31 */
+};
+
+/*
+ * Local Functions
+ */
+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.
+ */
+void
+bfa_fcs_port_loop_init(struct bfa_fcs_port_s *port)
+{
+}
+
+/**
+ * Called by port to notify transition to online state.
+ */
+void
+bfa_fcs_port_loop_online(struct bfa_fcs_port_s *port)
+{
+
+ u8 num_alpa = port->port_topo.ploop.num_alpa;
+ u8 *alpa_pos_map = port->port_topo.ploop.alpa_pos_map;
+ struct bfa_fcs_rport_s *r_port;
+ int ii = 0;
+
+ /*
+ * If the port role is Initiator Mode, create Rports.
+ */
+ if (port->port_cfg.roles == BFA_PORT_ROLE_FCP_IM) {
+ /*
+ * Check if the ALPA positional bitmap is available.
+ * if not, we send PLOGI to all possible ALPAs.
+ */
+ if (num_alpa > 0) {
+ for (ii = 0; ii < num_alpa; ii++) {
+ /*
+ * ignore ALPA of bfa port
+ */
+ if (alpa_pos_map[ii] != port->pid) {
+ r_port = bfa_fcs_rport_create(port,
+ alpa_pos_map[ii]);
+ }
+ }
+ } else {
+ for (ii = 0; ii < MAX_ALPA_COUNT; ii++) {
+ /*
+ * ignore ALPA of bfa port
+ */
+ if ((port_loop_alpa_map[ii] > 0)
+ && (port_loop_alpa_map[ii] != port->pid))
+ bfa_fcs_port_loop_send_plogi(port,
+ port_loop_alpa_map[ii]);
+ /**TBD */
+ }
+ }
+ } else {
+ /*
+ * TBD Target Mode ??
+ */
+ }
+
+}
+
+/**
+ * Called by port to notify transition to offline state.
+ */
+void
+bfa_fcs_port_loop_offline(struct bfa_fcs_port_s *port)
+{
+
+}
+
+/**
+ * Called by port to notify a LIP on the loop.
+ */
+void
+bfa_fcs_port_loop_lip(struct bfa_fcs_port_s *port)
+{
+}
+
+/**
+ * Local Functions.
+ */
+static bfa_status_t
+bfa_fcs_port_loop_send_plogi(struct bfa_fcs_port_s *port, u8 alpa)
+{
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp = NULL;
+ 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_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_response, (void *)port,
+ FC_MAX_PDUSZ, FC_RA_TOV);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Called by fcxp to notify the Plogi response
+ */
+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)
+{
+ struct bfa_fcs_port_s *port = (struct bfa_fcs_port_s *) cbarg;
+ struct fc_logi_s *plogi_resp;
+ struct fc_els_cmd_s *els_cmd;
+
+ bfa_trc(port->fcs, req_status);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ /*
+ * @todo
+ * This could mean that the device with this APLA does not
+ * exist on the loop.
+ */
+
+ return;
+ }
+
+ els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
+ plogi_resp = (struct fc_logi_s *) els_cmd;
+
+ if (els_cmd->els_code == FC_ELS_ACC) {
+ bfa_fcs_rport_start(port, rsp_fchs, plogi_resp);
+ } else {
+ bfa_trc(port->fcs, plogi_resp->els_cmd.els_code);
+ bfa_assert(0);
+ }
+}
diff --git a/drivers/scsi/bfa/lport_api.c b/drivers/scsi/bfa/lport_api.c
new file mode 100644
index 000000000000..1e06792cd4c2
--- /dev/null
+++ b/drivers/scsi/bfa/lport_api.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * port_api.c BFA FCS port
+ */
+
+#include <fcs/bfa_fcs.h>
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_rport.h>
+#include "fcs_rport.h"
+#include "fcs_fabric.h"
+#include "fcs_trcmod.h"
+#include "fcs_vport.h"
+
+BFA_TRC_FILE(FCS, PORT_API);
+
+
+
+/**
+ * fcs_port_api BFA FCS port API
+ */
+
+void
+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;
+}
+
+wwn_t
+bfa_fcs_port_get_rport(struct bfa_fcs_port_s *port, wwn_t wwn, int index,
+ int nrports, bfa_boolean_t bwwn)
+{
+ struct list_head *qh, *qe;
+ struct bfa_fcs_rport_s *rport = NULL;
+ int i;
+ struct bfa_fcs_s *fcs;
+
+ if (port == NULL || nrports == 0)
+ return (wwn_t) 0;
+
+ fcs = port->fcs;
+ bfa_trc(fcs, (u32) nrports);
+
+ i = 0;
+ qh = &port->rport_q;
+ qe = bfa_q_first(qh);
+
+ while ((qe != qh) && (i < nrports)) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) {
+ qe = bfa_q_next(qe);
+ bfa_trc(fcs, (u32) rport->pwwn);
+ bfa_trc(fcs, rport->pid);
+ bfa_trc(fcs, i);
+ continue;
+ }
+
+ if (bwwn) {
+ if (!memcmp(&wwn, &rport->pwwn, 8))
+ break;
+ } else {
+ if (i == index)
+ break;
+ }
+
+ i++;
+ qe = bfa_q_next(qe);
+ }
+
+ bfa_trc(fcs, i);
+ if (rport)
+ return rport->pwwn;
+ else
+ return (wwn_t) 0;
+}
+
+void
+bfa_fcs_port_get_rports(struct bfa_fcs_port_s *port, wwn_t rport_wwns[],
+ int *nrports)
+{
+ struct list_head *qh, *qe;
+ struct bfa_fcs_rport_s *rport = NULL;
+ int i;
+ struct bfa_fcs_s *fcs;
+
+ if (port == NULL || rport_wwns == NULL || *nrports == 0)
+ return;
+
+ fcs = port->fcs;
+ bfa_trc(fcs, (u32) *nrports);
+
+ i = 0;
+ qh = &port->rport_q;
+ qe = bfa_q_first(qh);
+
+ while ((qe != qh) && (i < *nrports)) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ if (bfa_os_ntoh3b(rport->pid) > 0xFFF000) {
+ qe = bfa_q_next(qe);
+ bfa_trc(fcs, (u32) rport->pwwn);
+ bfa_trc(fcs, rport->pid);
+ bfa_trc(fcs, i);
+ continue;
+ }
+
+ rport_wwns[i] = rport->pwwn;
+
+ i++;
+ qe = bfa_q_next(qe);
+ }
+
+ bfa_trc(fcs, i);
+ *nrports = i;
+ return;
+}
+
+/*
+ * Iterate's through all the rport's in the given port to
+ * determine the maximum operating speed.
+ */
+enum bfa_pport_speed
+bfa_fcs_port_get_rport_max_speed(struct bfa_fcs_port_s *port)
+{
+ struct list_head *qh, *qe;
+ struct bfa_fcs_rport_s *rport = NULL;
+ struct bfa_fcs_s *fcs;
+ enum bfa_pport_speed max_speed = 0;
+ struct bfa_pport_attr_s pport_attr;
+ enum bfa_pport_speed pport_speed;
+
+ if (port == NULL)
+ return 0;
+
+ fcs = port->fcs;
+
+ /*
+ * Get Physical port's current speed
+ */
+ bfa_pport_get_attr(port->fcs->bfa, &pport_attr);
+ pport_speed = pport_attr.speed;
+ bfa_trc(fcs, pport_speed);
+
+ qh = &port->rport_q;
+ qe = bfa_q_first(qh);
+
+ while (qe != qh) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ if ((bfa_os_ntoh3b(rport->pid) > 0xFFF000)
+ || (bfa_fcs_rport_get_state(rport) == BFA_RPORT_OFFLINE)) {
+ qe = bfa_q_next(qe);
+ continue;
+ }
+
+ if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_8GBPS)
+ || (rport->rpf.rpsc_speed > pport_speed)) {
+ max_speed = rport->rpf.rpsc_speed;
+ break;
+ } else if (rport->rpf.rpsc_speed > max_speed) {
+ max_speed = rport->rpf.rpsc_speed;
+ }
+
+ qe = bfa_q_next(qe);
+ }
+
+ bfa_trc(fcs, max_speed);
+ return max_speed;
+}
+
+struct bfa_fcs_port_s *
+bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn)
+{
+ struct bfa_fcs_vport_s *vport;
+ bfa_fcs_vf_t *vf;
+
+ bfa_assert(fcs != NULL);
+
+ vf = bfa_fcs_vf_lookup(fcs, vf_id);
+ if (vf == NULL) {
+ bfa_trc(fcs, vf_id);
+ return NULL;
+ }
+
+ if (!lpwwn || (vf->bport.port_cfg.pwwn == lpwwn))
+ return &vf->bport;
+
+ vport = bfa_fcs_fabric_vport_lookup(vf, lpwwn);
+ if (vport)
+ return &vport->lport;
+
+ return NULL;
+}
+
+/*
+ * API corresponding to VmWare's NPIV_VPORT_GETINFO.
+ */
+void
+bfa_fcs_port_get_info(struct bfa_fcs_port_s *port,
+ struct bfa_port_info_s *port_info)
+{
+
+ bfa_trc(port->fcs, port->fabric->fabric_name);
+
+ if (port->vport == NULL) {
+ /*
+ * This is a Physical port
+ */
+ port_info->port_type = BFA_PORT_TYPE_PHYSICAL;
+
+ /*
+ * @todo : need to fix the state & reason
+ */
+ port_info->port_state = 0;
+ port_info->offline_reason = 0;
+
+ port_info->port_wwn = bfa_fcs_port_get_pwwn(port);
+ port_info->node_wwn = bfa_fcs_port_get_nwwn(port);
+
+ port_info->max_vports_supp = bfa_fcs_vport_get_max(port->fcs);
+ port_info->num_vports_inuse =
+ bfa_fcs_fabric_vport_count(port->fabric);
+ port_info->max_rports_supp = BFA_FCS_MAX_RPORTS_SUPP;
+ port_info->num_rports_inuse = port->num_rports;
+ } else {
+ /*
+ * This is a virtual port
+ */
+ port_info->port_type = BFA_PORT_TYPE_VIRTUAL;
+
+ /*
+ * @todo : need to fix the state & reason
+ */
+ port_info->port_state = 0;
+ port_info->offline_reason = 0;
+
+ port_info->port_wwn = bfa_fcs_port_get_pwwn(port);
+ port_info->node_wwn = bfa_fcs_port_get_nwwn(port);
+ }
+}
+
+void
+bfa_fcs_port_get_stats(struct bfa_fcs_port_s *fcs_port,
+ struct bfa_port_stats_s *port_stats)
+{
+ bfa_os_memcpy(port_stats, &fcs_port->stats,
+ sizeof(struct bfa_port_stats_s));
+ return;
+}
+
+void
+bfa_fcs_port_clear_stats(struct bfa_fcs_port_s *fcs_port)
+{
+ bfa_os_memset(&fcs_port->stats, 0, sizeof(struct bfa_port_stats_s));
+ return;
+}
+
+void
+bfa_fcs_port_enable_ipfc_roles(struct bfa_fcs_port_s *fcs_port)
+{
+ fcs_port->port_cfg.roles |= BFA_PORT_ROLE_FCP_IPFC;
+ return;
+}
+
+void
+bfa_fcs_port_disable_ipfc_roles(struct bfa_fcs_port_s *fcs_port)
+{
+ fcs_port->port_cfg.roles &= ~BFA_PORT_ROLE_FCP_IPFC;
+ return;
+}
+
+
diff --git a/drivers/scsi/bfa/lport_priv.h b/drivers/scsi/bfa/lport_priv.h
new file mode 100644
index 000000000000..dbae370a599a
--- /dev/null
+++ b/drivers/scsi/bfa/lport_priv.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef __VP_PRIV_H__
+#define __VP_PRIV_H__
+
+#include <fcs/bfa_fcs_lport.h>
+#include <fcs/bfa_fcs_vport.h>
+
+/*
+ * Functions exported by vps
+ */
+void bfa_fcs_vport_init(struct bfa_fcs_vport_s *vport);
+
+/*
+ * Functions exported by vps
+ */
+void bfa_fcs_vps_online(struct bfa_fcs_port_s *port);
+void bfa_fcs_vps_offline(struct bfa_fcs_port_s *port);
+void bfa_fcs_vps_lip(struct bfa_fcs_port_s *port);
+
+/*
+ * Functions exported by port_fab
+ */
+void bfa_fcs_port_fab_init(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_fab_online(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_fab_offline(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_fab_rx_frame(struct bfa_fcs_port_s *port,
+ u8 *rx_frame, u32 len);
+
+/*
+ * Functions exported by VP-NS.
+ */
+void bfa_fcs_port_ns_init(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_ns_offline(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_ns_online(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_ns_query(struct bfa_fcs_port_s *port);
+
+/*
+ * Functions exported by VP-SCN
+ */
+void bfa_fcs_port_scn_init(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_scn_offline(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_scn_online(struct bfa_fcs_port_s *vport);
+void bfa_fcs_port_scn_process_rscn(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_frame, u32 len);
+
+/*
+ * Functions exported by VP-N2N
+ */
+
+void bfa_fcs_port_n2n_init(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_n2n_online(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_n2n_offline(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_n2n_rx_frame(struct bfa_fcs_port_s *port,
+ u8 *rx_frame, u32 len);
+
+/*
+ * Functions exported by VP-LOOP
+ */
+void bfa_fcs_port_loop_init(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_loop_online(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_loop_offline(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_loop_lip(struct bfa_fcs_port_s *port);
+void bfa_fcs_port_loop_rx_frame(struct bfa_fcs_port_s *port,
+ u8 *rx_frame, u32 len);
+
+#endif /* __VP_PRIV_H__ */
diff --git a/drivers/scsi/bfa/ms.c b/drivers/scsi/bfa/ms.c
new file mode 100644
index 000000000000..c96b3ca007ae
--- /dev/null
+++ b/drivers/scsi/bfa/ms.c
@@ -0,0 +1,759 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "lport_priv.h"
+
+BFA_TRC_FILE(FCS, MS);
+
+#define BFA_FCS_MS_CMD_MAX_RETRIES 2
+/*
+ * forward declarations
+ */
+static void bfa_fcs_port_ms_send_plogi(void *ms_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ms_timeout(void *arg);
+static void bfa_fcs_port_ms_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);
+
+static void bfa_fcs_port_ms_send_gmal(void *ms_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ms_gmal_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 void bfa_fcs_port_ms_send_gfn(void *ms_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ms_gfn_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);
+/**
+ * fcs_ms_sm FCS MS state machine
+ */
+
+/**
+ * MS State Machine events
+ */
+enum port_ms_event {
+ MSSM_EVENT_PORT_ONLINE = 1,
+ MSSM_EVENT_PORT_OFFLINE = 2,
+ MSSM_EVENT_RSP_OK = 3,
+ MSSM_EVENT_RSP_ERROR = 4,
+ MSSM_EVENT_TIMEOUT = 5,
+ MSSM_EVENT_FCXP_SENT = 6,
+ MSSM_EVENT_PORT_FABRIC_RSCN = 7
+};
+
+static void bfa_fcs_port_ms_sm_offline(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_plogi_sending(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_plogi_retry(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gmal_sending(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gmal_retry(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gfn_sending(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_gfn_retry(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+static void bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event);
+/**
+ * Start in offline state - awaiting NS to send start.
+ */
+static void
+bfa_fcs_port_ms_sm_offline(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event)
+{
+ bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
+ bfa_trc(ms->port->fcs, event);
+
+ switch (event) {
+ case MSSM_EVENT_PORT_ONLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_sending);
+ bfa_fcs_port_ms_send_plogi(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_plogi_sending(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event)
+{
+ bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
+ bfa_trc(ms->port->fcs, event);
+
+ switch (event) {
+ case MSSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
+ &ms->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_plogi(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
+{
+ bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
+ bfa_trc(ms->port->fcs, event);
+
+ switch (event) {
+ case MSSM_EVENT_RSP_ERROR:
+ /*
+ * Start timer for a delayed retry
+ */
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), &ms->timer,
+ bfa_fcs_port_ms_timeout, ms,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case MSSM_EVENT_RSP_OK:
+ /*
+ * since plogi is done, now invoke MS related sub-modules
+ */
+ bfa_fcs_port_fdmi_online(ms);
+
+ /**
+ * if this is a Vport, go to online state.
+ */
+ if (ms->port->vport) {
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online);
+ break;
+ }
+
+ /*
+ * For a base port we need to get the
+ * switch's IP address.
+ */
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_sending);
+ bfa_fcs_port_ms_send_gmal(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_discard(ms->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_plogi_retry(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event)
+{
+ bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
+ bfa_trc(ms->port->fcs, event);
+
+ switch (event) {
+ case MSSM_EVENT_TIMEOUT:
+ /*
+ * Retry Timer Expired. Re-send
+ */
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_plogi_sending);
+ bfa_fcs_port_ms_send_plogi(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_timer_stop(&ms->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_online(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event)
+{
+ bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
+ bfa_trc(ms->port->fcs, event);
+
+ switch (event) {
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ /*
+ * now invoke MS related sub-modules
+ */
+ bfa_fcs_port_fdmi_offline(ms);
+ break;
+
+ case MSSM_EVENT_PORT_FABRIC_RSCN:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending);
+ ms->retry_cnt = 0;
+ bfa_fcs_port_ms_send_gfn(ms, NULL);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_gmal_sending(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event)
+{
+ bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
+ bfa_trc(ms->port->fcs, event);
+
+ switch (event) {
+ case MSSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
+ &ms->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_gmal(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
+{
+ bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
+ bfa_trc(ms->port->fcs, event);
+
+ switch (event) {
+ case MSSM_EVENT_RSP_ERROR:
+ /*
+ * Start timer for a delayed retry
+ */
+ if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) {
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
+ &ms->timer, bfa_fcs_port_ms_timeout, ms,
+ BFA_FCS_RETRY_TIMEOUT);
+ } else {
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending);
+ bfa_fcs_port_ms_send_gfn(ms, NULL);
+ ms->retry_cnt = 0;
+ }
+ break;
+
+ case MSSM_EVENT_RSP_OK:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending);
+ bfa_fcs_port_ms_send_gfn(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_discard(ms->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_gmal_retry(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event)
+{
+ bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
+ bfa_trc(ms->port->fcs, event);
+
+ switch (event) {
+ case MSSM_EVENT_TIMEOUT:
+ /*
+ * Retry Timer Expired. Re-send
+ */
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gmal_sending);
+ bfa_fcs_port_ms_send_gmal(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_timer_stop(&ms->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * ms_pvt MS local functions
+ */
+
+static void
+bfa_fcs_port_ms_send_gmal(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ms_s *ms = ms_cbarg;
+ struct bfa_fcs_port_s *port = ms->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(port->fcs, port->pid);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
+ bfa_fcs_port_ms_send_gmal, ms);
+ return;
+ }
+ ms->fcxp = fcxp;
+
+ len = fc_gmal_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_fcs_port_get_fcid(port),
+ bfa_lps_get_peer_nwwn(port->fabric->lps));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gmal_response,
+ (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_port_ms_gmal_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_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg;
+ struct bfa_fcs_port_s *port = ms->port;
+ struct ct_hdr_s *cthdr = NULL;
+ struct fcgs_gmal_resp_s *gmal_resp;
+ struct fc_gmal_entry_s *gmal_entry;
+ u32 num_entries;
+ u8 *rsp_str;
+
+ bfa_trc(port->fcs, req_status);
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
+ cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
+ gmal_resp = (struct fcgs_gmal_resp_s *)(cthdr + 1);
+ num_entries = bfa_os_ntohl(gmal_resp->ms_len);
+ if (num_entries == 0) {
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
+ return;
+ }
+ /*
+ * The response could contain multiple Entries.
+ * Entries for SNMP interface, etc.
+ * We look for the entry with a telnet prefix.
+ * First "http://" entry refers to IP addr
+ */
+
+ gmal_entry = (struct fc_gmal_entry_s *)gmal_resp->ms_ma;
+ while (num_entries > 0) {
+ if (strncmp
+ (gmal_entry->prefix, CT_GMAL_RESP_PREFIX_HTTP,
+ sizeof(gmal_entry->prefix)) == 0) {
+
+ /*
+ * if the IP address is terminating with a '/',
+ * remove it. *Byte 0 consists of the length
+ * of the string.
+ */
+ rsp_str = &(gmal_entry->prefix[0]);
+ if (rsp_str[gmal_entry->len - 1] == '/')
+ rsp_str[gmal_entry->len - 1] = 0;
+ /*
+ * copy IP Address to fabric
+ */
+ strncpy(bfa_fcs_port_get_fabric_ipaddr(port),
+ gmal_entry->ip_addr,
+ BFA_FCS_FABRIC_IPADDR_SZ);
+ break;
+ } else {
+ --num_entries;
+ ++gmal_entry;
+ }
+ }
+
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK);
+ return;
+ }
+
+ bfa_trc(port->fcs, cthdr->reason_code);
+ bfa_trc(port->fcs, cthdr->exp_code);
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
+}
+
+static void
+bfa_fcs_port_ms_sm_gfn_sending(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event)
+{
+ bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
+ bfa_trc(ms->port->fcs, event);
+
+ switch (event) {
+ case MSSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
+ &ms->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_gfn(struct bfa_fcs_port_ms_s *ms, enum port_ms_event event)
+{
+ bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
+ bfa_trc(ms->port->fcs, event);
+
+ switch (event) {
+ case MSSM_EVENT_RSP_ERROR:
+ /*
+ * Start timer for a delayed retry
+ */
+ if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) {
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_retry);
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port),
+ &ms->timer, bfa_fcs_port_ms_timeout, ms,
+ BFA_FCS_RETRY_TIMEOUT);
+ } else {
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online);
+ ms->retry_cnt = 0;
+ }
+ break;
+
+ case MSSM_EVENT_RSP_OK:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_online);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_fcxp_discard(ms->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ms_sm_gfn_retry(struct bfa_fcs_port_ms_s *ms,
+ enum port_ms_event event)
+{
+ bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn);
+ bfa_trc(ms->port->fcs, event);
+
+ switch (event) {
+ case MSSM_EVENT_TIMEOUT:
+ /*
+ * Retry Timer Expired. Re-send
+ */
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_gfn_sending);
+ bfa_fcs_port_ms_send_gfn(ms, NULL);
+ break;
+
+ case MSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+ bfa_timer_stop(&ms->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * ms_pvt MS local functions
+ */
+
+static void
+bfa_fcs_port_ms_send_gfn(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ms_s *ms = ms_cbarg;
+ struct bfa_fcs_port_s *port = ms->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(port->fcs, port->pid);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
+ bfa_fcs_port_ms_send_gfn, ms);
+ return;
+ }
+ ms->fcxp = fcxp;
+
+ len = fc_gfn_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_fcs_port_get_fcid(port),
+ bfa_lps_get_peer_nwwn(port->fabric->lps));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_port_ms_gfn_response,
+ (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_port_ms_gfn_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_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg;
+ struct bfa_fcs_port_s *port = ms->port;
+ struct ct_hdr_s *cthdr = NULL;
+ wwn_t *gfn_resp;
+
+ bfa_trc(port->fcs, req_status);
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
+ cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
+ gfn_resp = (wwn_t *) (cthdr + 1);
+ /*
+ * check if it has actually changed
+ */
+ if ((memcmp
+ ((void *)&bfa_fcs_port_get_fabric_name(port), gfn_resp,
+ sizeof(wwn_t)) != 0))
+ bfa_fcs_fabric_set_fabric_name(port->fabric, *gfn_resp);
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK);
+ return;
+ }
+
+ bfa_trc(port->fcs, cthdr->reason_code);
+ bfa_trc(port->fcs, cthdr->exp_code);
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
+}
+
+/**
+ * ms_pvt MS local functions
+ */
+
+static void
+bfa_fcs_port_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ms_s *ms = ms_cbarg;
+ struct bfa_fcs_port_s *port = ms->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(port->fcs, port->pid);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ port->stats.ms_plogi_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe,
+ bfa_fcs_port_ms_send_plogi, ms);
+ return;
+ }
+ ms->fcxp = fcxp;
+
+ len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_os_hton3b(FC_MGMT_SERVER),
+ 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_ms_plogi_response,
+ (void *)ms, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ port->stats.ms_plogi_sent++;
+ bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_port_ms_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)
+{
+ struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)cbarg;
+
+ struct bfa_fcs_port_s *port = ms->port;
+ struct fc_els_cmd_s *els_cmd;
+ struct fc_ls_rjt_s *ls_rjt;
+
+ bfa_trc(port->fcs, req_status);
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ port->stats.ms_plogi_rsp_err++;
+ bfa_trc(port->fcs, req_status);
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ switch (els_cmd->els_code) {
+
+ case FC_ELS_ACC:
+ if (rsp_len < sizeof(struct fc_logi_s)) {
+ bfa_trc(port->fcs, rsp_len);
+ port->stats.ms_plogi_acc_err++;
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
+ break;
+ }
+ port->stats.ms_plogi_accepts++;
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK);
+ break;
+
+ case FC_ELS_LS_RJT:
+ ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ bfa_trc(port->fcs, ls_rjt->reason_code);
+ bfa_trc(port->fcs, ls_rjt->reason_code_expl);
+
+ port->stats.ms_rejects++;
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
+ break;
+
+ default:
+ port->stats.ms_plogi_unknown_rsp++;
+ bfa_trc(port->fcs, els_cmd->els_code);
+ bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR);
+ }
+}
+
+static void
+bfa_fcs_port_ms_timeout(void *arg)
+{
+ struct bfa_fcs_port_ms_s *ms = (struct bfa_fcs_port_ms_s *)arg;
+
+ ms->port->stats.ms_timeouts++;
+ bfa_sm_send_event(ms, MSSM_EVENT_TIMEOUT);
+}
+
+
+void
+bfa_fcs_port_ms_init(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);
+
+ ms->port = port;
+ bfa_sm_set_state(ms, bfa_fcs_port_ms_sm_offline);
+
+ /*
+ * Invoke init routines of sub modules.
+ */
+ bfa_fcs_port_fdmi_init(ms);
+}
+
+void
+bfa_fcs_port_ms_offline(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);
+
+ ms->port = port;
+ bfa_sm_send_event(ms, MSSM_EVENT_PORT_OFFLINE);
+}
+
+void
+bfa_fcs_port_ms_online(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);
+
+ ms->port = port;
+ bfa_sm_send_event(ms, MSSM_EVENT_PORT_ONLINE);
+}
+
+void
+bfa_fcs_port_ms_fabric_rscn(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port);
+
+ /*
+ * @todo. Handle this only when in Online state
+ */
+ if (bfa_sm_cmp_state(ms, bfa_fcs_port_ms_sm_online))
+ bfa_sm_send_event(ms, MSSM_EVENT_PORT_FABRIC_RSCN);
+}
diff --git a/drivers/scsi/bfa/n2n.c b/drivers/scsi/bfa/n2n.c
new file mode 100644
index 000000000000..735456824346
--- /dev/null
+++ b/drivers/scsi/bfa/n2n.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * n2n.c n2n implementation.
+ */
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_trcmod.h"
+#include "lport_priv.h"
+
+BFA_TRC_FILE(FCS, N2N);
+
+/**
+ * Called by fcs/port to initialize N2N topology.
+ */
+void
+bfa_fcs_port_n2n_init(struct bfa_fcs_port_s *port)
+{
+}
+
+/**
+ * Called by fcs/port to notify transition to online state.
+ */
+void
+bfa_fcs_port_n2n_online(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_n2n_s *n2n_port = &port->port_topo.pn2n;
+ struct bfa_port_cfg_s *pcfg = &port->port_cfg;
+ struct bfa_fcs_rport_s *rport;
+
+ bfa_trc(port->fcs, pcfg->pwwn);
+
+ /*
+ * If our PWWN is > than that of the r-port, we have to initiate PLOGI
+ * and assign an Address. if not, we need to wait for its PLOGI.
+ *
+ * If our PWWN is < than that of the remote port, it will send a PLOGI
+ * with the PIDs assigned. The rport state machine take care of this
+ * incoming PLOGI.
+ */
+ if (memcmp
+ ((void *)&pcfg->pwwn, (void *)&n2n_port->rem_port_wwn,
+ sizeof(wwn_t)) > 0) {
+ port->pid = N2N_LOCAL_PID;
+ /**
+ * First, check if we know the device by pwwn.
+ */
+ rport = bfa_fcs_port_get_rport_by_pwwn(port,
+ n2n_port->rem_port_wwn);
+ if (rport) {
+ bfa_trc(port->fcs, rport->pid);
+ bfa_trc(port->fcs, rport->pwwn);
+ rport->pid = N2N_REMOTE_PID;
+ bfa_fcs_rport_online(rport);
+ return;
+ }
+
+ /*
+ * In n2n there can be only one rport. Delete the old one whose
+ * pid should be zero, because it is offline.
+ */
+ if (port->num_rports > 0) {
+ rport = bfa_fcs_port_get_rport_by_pid(port, 0);
+ bfa_assert(rport != NULL);
+ if (rport) {
+ bfa_trc(port->fcs, rport->pwwn);
+ bfa_fcs_rport_delete(rport);
+ }
+ }
+ bfa_fcs_rport_create(port, N2N_REMOTE_PID);
+ }
+}
+
+/**
+ * Called by fcs/port to notify transition to offline state.
+ */
+void
+bfa_fcs_port_n2n_offline(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_n2n_s *n2n_port = &port->port_topo.pn2n;
+
+ bfa_trc(port->fcs, port->pid);
+ port->pid = 0;
+ n2n_port->rem_port_wwn = 0;
+ n2n_port->reply_oxid = 0;
+}
+
+
diff --git a/drivers/scsi/bfa/ns.c b/drivers/scsi/bfa/ns.c
new file mode 100644
index 000000000000..2f8b880060bb
--- /dev/null
+++ b/drivers/scsi/bfa/ns.c
@@ -0,0 +1,1242 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * @page ns_sm_info VPORT NS State Machine
+ *
+ * @section ns_sm_interactions VPORT NS State Machine Interactions
+ *
+ * @section ns_sm VPORT NS State Machine
+ * img ns_sm.jpg
+ */
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <bfa_iocfc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs.h"
+#include "lport_priv.h"
+
+BFA_TRC_FILE(FCS, NS);
+
+/*
+ * forward declarations
+ */
+static void bfa_fcs_port_ns_send_plogi(void *ns_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ns_send_rspn_id(void *ns_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ns_send_rft_id(void *ns_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ns_send_rff_id(void *ns_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ns_send_gid_ft(void *ns_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_ns_timeout(void *arg);
+static void bfa_fcs_port_ns_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);
+static void bfa_fcs_port_ns_rspn_id_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 void bfa_fcs_port_ns_rft_id_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 void bfa_fcs_port_ns_rff_id_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 void bfa_fcs_port_ns_gid_ft_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 void bfa_fcs_port_ns_process_gidft_pids(struct bfa_fcs_port_s *port,
+ u32 *pid_buf,
+ u32 n_pids);
+
+static void bfa_fcs_port_ns_boot_target_disc(struct bfa_fcs_port_s *port);
+/**
+ * fcs_ns_sm FCS nameserver interface state machine
+ */
+
+/**
+ * VPort NS State Machine events
+ */
+enum vport_ns_event {
+ NSSM_EVENT_PORT_ONLINE = 1,
+ NSSM_EVENT_PORT_OFFLINE = 2,
+ NSSM_EVENT_PLOGI_SENT = 3,
+ NSSM_EVENT_RSP_OK = 4,
+ NSSM_EVENT_RSP_ERROR = 5,
+ NSSM_EVENT_TIMEOUT = 6,
+ NSSM_EVENT_NS_QUERY = 7,
+ NSSM_EVENT_RSPNID_SENT = 8,
+ NSSM_EVENT_RFTID_SENT = 9,
+ NSSM_EVENT_RFFID_SENT = 10,
+ NSSM_EVENT_GIDFT_SENT = 11,
+};
+
+static void bfa_fcs_port_ns_sm_offline(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_plogi_sending(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_plogi(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_plogi_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_sending_rspn_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rspn_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rspn_id_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_sending_rft_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rft_id_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rft_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_sending_rff_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rff_id_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_rff_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_sending_gid_ft(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_gid_ft(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_gid_ft_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+static void bfa_fcs_port_ns_sm_online(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event);
+/**
+ * Start in offline state - awaiting linkup
+ */
+static void
+bfa_fcs_port_ns_sm_offline(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_PORT_ONLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_sending);
+ bfa_fcs_port_ns_send_plogi(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_plogi_sending(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_PLOGI_SENT:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
+ &ns->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_plogi(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_RSP_ERROR:
+ /*
+ * Start timer for a delayed retry
+ */
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_retry);
+ ns->port->stats.ns_retries++;
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer,
+ bfa_fcs_port_ns_timeout, ns,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case NSSM_EVENT_RSP_OK:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rspn_id);
+ bfa_fcs_port_ns_send_rspn_id(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_discard(ns->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_plogi_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_TIMEOUT:
+ /*
+ * Retry Timer Expired. Re-send
+ */
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_plogi_sending);
+ bfa_fcs_port_ns_send_plogi(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_timer_stop(&ns->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_sending_rspn_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_RSPNID_SENT:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rspn_id);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
+ &ns->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rspn_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_RSP_ERROR:
+ /*
+ * Start timer for a delayed retry
+ */
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rspn_id_retry);
+ ns->port->stats.ns_retries++;
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer,
+ bfa_fcs_port_ns_timeout, ns,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case NSSM_EVENT_RSP_OK:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rft_id);
+ bfa_fcs_port_ns_send_rft_id(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_fcxp_discard(ns->fcxp);
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rspn_id_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_TIMEOUT:
+ /*
+ * Retry Timer Expired. Re-send
+ */
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rspn_id);
+ bfa_fcs_port_ns_send_rspn_id(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_timer_stop(&ns->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_sending_rft_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_RFTID_SENT:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rft_id);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
+ &ns->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rft_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_RSP_OK:
+ /*
+ * Now move to register FC4 Features
+ */
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rff_id);
+ bfa_fcs_port_ns_send_rff_id(ns, NULL);
+ break;
+
+ case NSSM_EVENT_RSP_ERROR:
+ /*
+ * Start timer for a delayed retry
+ */
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rft_id_retry);
+ ns->port->stats.ns_retries++;
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer,
+ bfa_fcs_port_ns_timeout, ns,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_discard(ns->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rft_id_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_TIMEOUT:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rft_id);
+ bfa_fcs_port_ns_send_rft_id(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_timer_stop(&ns->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_sending_rff_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_RFFID_SENT:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rff_id);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
+ &ns->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rff_id(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_RSP_OK:
+
+ /*
+ * If min cfg mode is enabled, we donot initiate rport
+ * discovery with the fabric. Instead, we will retrieve the
+ * boot targets from HAL/FW.
+ */
+ if (__fcs_min_cfg(ns->port->fcs)) {
+ bfa_fcs_port_ns_boot_target_disc(ns->port);
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online);
+ return;
+ }
+
+ /*
+ * If the port role is Initiator Mode issue NS query.
+ * If it is Target Mode, skip this and go to online.
+ */
+ if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) {
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft);
+ bfa_fcs_port_ns_send_gid_ft(ns, NULL);
+ } else if (BFA_FCS_VPORT_IS_TARGET_MODE(ns->port)) {
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online);
+ }
+ /*
+ * kick off mgmt srvr state machine
+ */
+ bfa_fcs_port_ms_online(ns->port);
+ break;
+
+ case NSSM_EVENT_RSP_ERROR:
+ /*
+ * Start timer for a delayed retry
+ */
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_rff_id_retry);
+ ns->port->stats.ns_retries++;
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer,
+ bfa_fcs_port_ns_timeout, ns,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_discard(ns->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_rff_id_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_TIMEOUT:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_rff_id);
+ bfa_fcs_port_ns_send_rff_id(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_timer_stop(&ns->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+static void
+bfa_fcs_port_ns_sm_sending_gid_ft(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_GIDFT_SENT:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_gid_ft);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port),
+ &ns->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_gid_ft(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_RSP_OK:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_online);
+ break;
+
+ case NSSM_EVENT_RSP_ERROR:
+ /*
+ * TBD: for certain reject codes, we don't need to retry
+ */
+ /*
+ * Start timer for a delayed retry
+ */
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_gid_ft_retry);
+ ns->port->stats.ns_retries++;
+ bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), &ns->timer,
+ bfa_fcs_port_ns_timeout, ns,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_fcxp_discard(ns->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_gid_ft_retry(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_TIMEOUT:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft);
+ bfa_fcs_port_ns_send_gid_ft(ns, NULL);
+ break;
+
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ bfa_timer_stop(&ns->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_ns_sm_online(struct bfa_fcs_port_ns_s *ns,
+ enum vport_ns_event event)
+{
+ bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn);
+ bfa_trc(ns->port->fcs, event);
+
+ switch (event) {
+ case NSSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+ break;
+
+ case NSSM_EVENT_NS_QUERY:
+ /*
+ * If the port role is Initiator Mode issue NS query.
+ * If it is Target Mode, skip this and go to online.
+ */
+ if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) {
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_sending_gid_ft);
+ bfa_fcs_port_ns_send_gid_ft(ns, NULL);
+ };
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * ns_pvt Nameserver local functions
+ */
+
+static void
+bfa_fcs_port_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ns_s *ns = ns_cbarg;
+ struct bfa_fcs_port_s *port = ns->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(port->fcs, port->pid);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ port->stats.ns_plogi_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
+ bfa_fcs_port_ns_send_plogi, ns);
+ return;
+ }
+ ns->fcxp = fcxp;
+
+ len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_os_hton3b(FC_NAME_SERVER),
+ 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_ns_plogi_response,
+ (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+ port->stats.ns_plogi_sent++;
+
+ bfa_sm_send_event(ns, NSSM_EVENT_PLOGI_SENT);
+}
+
+static void
+bfa_fcs_port_ns_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)
+{
+ struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg;
+ struct bfa_fcs_port_s *port = ns->port;
+ /* struct fc_logi_s *plogi_resp; */
+ struct fc_els_cmd_s *els_cmd;
+ struct fc_ls_rjt_s *ls_rjt;
+
+ bfa_trc(port->fcs, req_status);
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ port->stats.ns_plogi_rsp_err++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ switch (els_cmd->els_code) {
+
+ case FC_ELS_ACC:
+ if (rsp_len < sizeof(struct fc_logi_s)) {
+ bfa_trc(port->fcs, rsp_len);
+ port->stats.ns_plogi_acc_err++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+ break;
+ }
+ port->stats.ns_plogi_accepts++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
+ break;
+
+ case FC_ELS_LS_RJT:
+ ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ bfa_trc(port->fcs, ls_rjt->reason_code);
+ bfa_trc(port->fcs, ls_rjt->reason_code_expl);
+
+ port->stats.ns_rejects++;
+
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+ break;
+
+ default:
+ port->stats.ns_plogi_unknown_rsp++;
+ bfa_trc(port->fcs, els_cmd->els_code);
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+ }
+}
+
+/**
+ * Register the symbolic port name.
+ */
+static void
+bfa_fcs_port_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ns_s *ns = ns_cbarg;
+ struct bfa_fcs_port_s *port = ns->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+ u8 symbl[256];
+ u8 *psymbl = &symbl[0];
+
+ bfa_os_memset(symbl, 0, sizeof(symbl));
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ port->stats.ns_rspnid_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
+ bfa_fcs_port_ns_send_rspn_id, ns);
+ return;
+ }
+ ns->fcxp = fcxp;
+
+ /*
+ * for V-Port, form a Port Symbolic Name
+ */
+ if (port->vport) {
+ /**For Vports,
+ * we append the vport's port symbolic name to that of the base port.
+ */
+
+ strncpy((char *)psymbl,
+ (char *)
+ &(bfa_fcs_port_get_psym_name
+ (bfa_fcs_get_base_port(port->fcs))),
+ strlen((char *)
+ &bfa_fcs_port_get_psym_name(bfa_fcs_get_base_port
+ (port->fcs))));
+
+ /*
+ * Ensure we have a null terminating string.
+ */
+ ((char *)
+ psymbl)[strlen((char *)
+ &bfa_fcs_port_get_psym_name
+ (bfa_fcs_get_base_port(port->fcs)))] = 0;
+
+ strncat((char *)psymbl,
+ (char *)&(bfa_fcs_port_get_psym_name(port)),
+ strlen((char *)&bfa_fcs_port_get_psym_name(port)));
+ } else {
+ psymbl = (u8 *) &(bfa_fcs_port_get_psym_name(port));
+ }
+
+ len = fc_rspnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_fcs_port_get_fcid(port), 0, psymbl);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rspn_id_response,
+ (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ port->stats.ns_rspnid_sent++;
+
+ bfa_sm_send_event(ns, NSSM_EVENT_RSPNID_SENT);
+}
+
+static void
+bfa_fcs_port_ns_rspn_id_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_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg;
+ struct bfa_fcs_port_s *port = ns->port;
+ struct ct_hdr_s *cthdr = NULL;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ port->stats.ns_rspnid_rsp_err++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
+ cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
+ port->stats.ns_rspnid_accepts++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
+ return;
+ }
+
+ port->stats.ns_rspnid_rejects++;
+ bfa_trc(port->fcs, cthdr->reason_code);
+ bfa_trc(port->fcs, cthdr->exp_code);
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+}
+
+/**
+ * Register FC4-Types
+ * TBD, Need to retrieve this from the OS driver, in case IPFC is enabled ?
+ */
+static void
+bfa_fcs_port_ns_send_rft_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ns_s *ns = ns_cbarg;
+ struct bfa_fcs_port_s *port = ns->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ port->stats.ns_rftid_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
+ bfa_fcs_port_ns_send_rft_id, ns);
+ return;
+ }
+ ns->fcxp = fcxp;
+
+ len = fc_rftid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_fcs_port_get_fcid(port), 0,
+ port->port_cfg.roles);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rft_id_response,
+ (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ port->stats.ns_rftid_sent++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RFTID_SENT);
+}
+
+static void
+bfa_fcs_port_ns_rft_id_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_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg;
+ struct bfa_fcs_port_s *port = ns->port;
+ struct ct_hdr_s *cthdr = NULL;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ port->stats.ns_rftid_rsp_err++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
+ cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
+ port->stats.ns_rftid_accepts++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
+ return;
+ }
+
+ port->stats.ns_rftid_rejects++;
+ bfa_trc(port->fcs, cthdr->reason_code);
+ bfa_trc(port->fcs, cthdr->exp_code);
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+}
+
+/**
+* Register FC4-Features : Should be done after RFT_ID
+ */
+static void
+bfa_fcs_port_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ns_s *ns = ns_cbarg;
+ struct bfa_fcs_port_s *port = ns->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+ u8 fc4_ftrs = 0;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ port->stats.ns_rffid_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
+ bfa_fcs_port_ns_send_rff_id, ns);
+ return;
+ }
+ ns->fcxp = fcxp;
+
+ 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))
+ 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,
+ fc4_ftrs);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_rff_id_response,
+ (void *)ns, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ port->stats.ns_rffid_sent++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RFFID_SENT);
+}
+
+static void
+bfa_fcs_port_ns_rff_id_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_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg;
+ struct bfa_fcs_port_s *port = ns->port;
+ struct ct_hdr_s *cthdr = NULL;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ port->stats.ns_rffid_rsp_err++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
+ cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
+ port->stats.ns_rffid_accepts++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
+ return;
+ }
+
+ port->stats.ns_rffid_rejects++;
+ bfa_trc(port->fcs, cthdr->reason_code);
+ bfa_trc(port->fcs, cthdr->exp_code);
+
+ if (cthdr->reason_code == CT_RSN_NOT_SUPP) {
+ /*
+ * if this command is not supported, we don't retry
+ */
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
+ } else {
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+ }
+}
+
+/**
+ * Query Fabric for FC4-Types Devices.
+ *
+* TBD : Need to use a local (FCS private) response buffer, since the response
+ * can be larger than 2K.
+ */
+static void
+bfa_fcs_port_ns_send_gid_ft(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_ns_s *ns = ns_cbarg;
+ struct bfa_fcs_port_s *port = ns->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(port->fcs, port->pid);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ port->stats.ns_gidft_alloc_wait++;
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe,
+ bfa_fcs_port_ns_send_gid_ft, ns);
+ return;
+ }
+ ns->fcxp = fcxp;
+
+ /*
+ * This query is only initiated for FCP initiator mode.
+ */
+ len = fc_gid_ft_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), ns->port->pid,
+ FC_TYPE_FCP);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_port_ns_gid_ft_response,
+ (void *)ns, bfa_fcxp_get_maxrsp(port->fcs->bfa),
+ FC_RA_TOV);
+
+ port->stats.ns_gidft_sent++;
+
+ bfa_sm_send_event(ns, NSSM_EVENT_GIDFT_SENT);
+}
+
+static void
+bfa_fcs_port_ns_gid_ft_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_ns_s *ns = (struct bfa_fcs_port_ns_s *)cbarg;
+ struct bfa_fcs_port_s *port = ns->port;
+ struct ct_hdr_s *cthdr = NULL;
+ u32 n_pids;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ port->stats.ns_gidft_rsp_err++;
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ if (resid_len != 0) {
+ /*
+ * TBD : we will need to allocate a larger buffer & retry the
+ * command
+ */
+ bfa_trc(port->fcs, rsp_len);
+ bfa_trc(port->fcs, resid_len);
+ return;
+ }
+
+ cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
+ cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ switch (cthdr->cmd_rsp_code) {
+
+ case CT_RSP_ACCEPT:
+
+ port->stats.ns_gidft_accepts++;
+ n_pids = (fc_get_ctresp_pyld_len(rsp_len) / sizeof(u32));
+ bfa_trc(port->fcs, n_pids);
+ bfa_fcs_port_ns_process_gidft_pids(port,
+ (u32 *) (cthdr + 1),
+ n_pids);
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
+ break;
+
+ case CT_RSP_REJECT:
+
+ /*
+ * Check the reason code & explanation.
+ * There may not have been any FC4 devices in the fabric
+ */
+ port->stats.ns_gidft_rejects++;
+ bfa_trc(port->fcs, cthdr->reason_code);
+ bfa_trc(port->fcs, cthdr->exp_code);
+
+ if ((cthdr->reason_code == CT_RSN_UNABLE_TO_PERF)
+ && (cthdr->exp_code == CT_NS_EXP_FT_NOT_REG)) {
+
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK);
+ } else {
+ /*
+ * for all other errors, retry
+ */
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+ }
+ break;
+
+ default:
+ port->stats.ns_gidft_unknown_rsp++;
+ bfa_trc(port->fcs, cthdr->cmd_rsp_code);
+ bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR);
+ }
+}
+
+/**
+ * This routine will be called by bfa_timer on timer timeouts.
+ *
+ * param[in] port - pointer to bfa_fcs_port_t.
+ *
+ * return
+ * void
+ *
+* Special Considerations:
+ *
+ * note
+ */
+static void
+bfa_fcs_port_ns_timeout(void *arg)
+{
+ struct bfa_fcs_port_ns_s *ns = (struct bfa_fcs_port_ns_s *)arg;
+
+ ns->port->stats.ns_timeouts++;
+ bfa_sm_send_event(ns, NSSM_EVENT_TIMEOUT);
+}
+
+/*
+ * Process the PID list in GID_FT response
+ */
+static void
+bfa_fcs_port_ns_process_gidft_pids(struct bfa_fcs_port_s *port,
+ u32 *pid_buf, u32 n_pids)
+{
+ struct fcgs_gidft_resp_s *gidft_entry;
+ struct bfa_fcs_rport_s *rport;
+ u32 ii;
+
+ for (ii = 0; ii < n_pids; ii++) {
+ gidft_entry = (struct fcgs_gidft_resp_s *) &pid_buf[ii];
+
+ if (gidft_entry->pid == port->pid)
+ continue;
+
+ /*
+ * Check if this rport already exists
+ */
+ rport = bfa_fcs_port_get_rport_by_pid(port, gidft_entry->pid);
+ if (rport == NULL) {
+ /*
+ * this is a new device. create rport
+ */
+ rport = bfa_fcs_rport_create(port, gidft_entry->pid);
+ } else {
+ /*
+ * this rport already exists
+ */
+ bfa_fcs_rport_scn(rport);
+ }
+
+ bfa_trc(port->fcs, gidft_entry->pid);
+
+ /*
+ * if the last entry bit is set, bail out.
+ */
+ if (gidft_entry->last)
+ return;
+ }
+}
+
+/**
+ * fcs_ns_public FCS nameserver public interfaces
+ */
+
+/*
+ * Functions called by port/fab.
+ * These will send relevant Events to the ns state machine.
+ */
+void
+bfa_fcs_port_ns_init(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port);
+
+ ns->port = port;
+ bfa_sm_set_state(ns, bfa_fcs_port_ns_sm_offline);
+}
+
+void
+bfa_fcs_port_ns_offline(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port);
+
+ ns->port = port;
+ bfa_sm_send_event(ns, NSSM_EVENT_PORT_OFFLINE);
+}
+
+void
+bfa_fcs_port_ns_online(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port);
+
+ ns->port = port;
+ bfa_sm_send_event(ns, NSSM_EVENT_PORT_ONLINE);
+}
+
+void
+bfa_fcs_port_ns_query(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port);
+
+ bfa_trc(port->fcs, port->pid);
+ bfa_sm_send_event(ns, NSSM_EVENT_NS_QUERY);
+}
+
+static void
+bfa_fcs_port_ns_boot_target_disc(struct bfa_fcs_port_s *port)
+{
+
+ struct bfa_fcs_rport_s *rport;
+ u8 nwwns;
+ wwn_t *wwns;
+ int ii;
+
+ bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, &wwns);
+
+ for (ii = 0; ii < nwwns; ++ii) {
+ rport = bfa_fcs_rport_create_by_wwn(port, wwns[ii]);
+ bfa_assert(rport);
+ }
+}
+
+
diff --git a/drivers/scsi/bfa/plog.c b/drivers/scsi/bfa/plog.c
new file mode 100644
index 000000000000..fcb8864d3276
--- /dev/null
+++ b/drivers/scsi/bfa/plog.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa_os_inc.h>
+#include <cs/bfa_plog.h>
+#include <cs/bfa_debug.h>
+
+static int
+plkd_validate_logrec(struct bfa_plog_rec_s *pl_rec)
+{
+ if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT)
+ && (pl_rec->log_type != BFA_PL_LOG_TYPE_STRING))
+ return 1;
+
+ if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT)
+ && (pl_rec->log_num_ints > BFA_PL_INT_LOG_SZ))
+ return 1;
+
+ return 0;
+}
+
+static void
+bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec)
+{
+ u16 tail;
+ struct bfa_plog_rec_s *pl_recp;
+
+ if (plog->plog_enabled == 0)
+ return;
+
+ if (plkd_validate_logrec(pl_rec)) {
+ bfa_assert(0);
+ return;
+ }
+
+ tail = plog->tail;
+
+ pl_recp = &(plog->plog_recs[tail]);
+
+ bfa_os_memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s));
+
+ pl_recp->tv = BFA_TRC_TS(plog);
+ BFA_PL_LOG_REC_INCR(plog->tail);
+
+ if (plog->head == plog->tail)
+ BFA_PL_LOG_REC_INCR(plog->head);
+}
+
+void
+bfa_plog_init(struct bfa_plog_s *plog)
+{
+ bfa_os_memset((char *)plog, 0, sizeof(struct bfa_plog_s));
+
+ bfa_os_memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN);
+ plog->head = plog->tail = 0;
+ plog->plog_enabled = 1;
+}
+
+void
+bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event,
+ u16 misc, char *log_str)
+{
+ struct bfa_plog_rec_s lp;
+
+ if (plog->plog_enabled) {
+ bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+ lp.mid = mid;
+ lp.eid = event;
+ lp.log_type = BFA_PL_LOG_TYPE_STRING;
+ lp.misc = misc;
+ strncpy(lp.log_entry.string_log, log_str,
+ BFA_PL_STRING_LOG_SZ - 1);
+ lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0';
+ bfa_plog_add(plog, &lp);
+ }
+}
+
+void
+bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event,
+ u16 misc, u32 *intarr, u32 num_ints)
+{
+ struct bfa_plog_rec_s lp;
+ u32 i;
+
+ if (num_ints > BFA_PL_INT_LOG_SZ)
+ num_ints = BFA_PL_INT_LOG_SZ;
+
+ if (plog->plog_enabled) {
+ bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+ lp.mid = mid;
+ lp.eid = event;
+ lp.log_type = BFA_PL_LOG_TYPE_INT;
+ lp.misc = misc;
+
+ for (i = 0; i < num_ints; i++)
+ bfa_os_assign(lp.log_entry.int_log[i],
+ intarr[i]);
+
+ lp.log_num_ints = (u8) num_ints;
+
+ bfa_plog_add(plog, &lp);
+ }
+}
+
+void
+bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event,
+ u16 misc, struct fchs_s *fchdr)
+{
+ struct bfa_plog_rec_s lp;
+ u32 *tmp_int = (u32 *) fchdr;
+ u32 ints[BFA_PL_INT_LOG_SZ];
+
+ if (plog->plog_enabled) {
+ bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+
+ ints[0] = tmp_int[0];
+ ints[1] = tmp_int[1];
+ ints[2] = tmp_int[4];
+
+ bfa_plog_intarr(plog, mid, event, misc, ints, 3);
+ }
+}
+
+void
+bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid,
+ enum bfa_plog_eid event, u16 misc, struct fchs_s *fchdr,
+ u32 pld_w0)
+{
+ struct bfa_plog_rec_s lp;
+ u32 *tmp_int = (u32 *) fchdr;
+ u32 ints[BFA_PL_INT_LOG_SZ];
+
+ if (plog->plog_enabled) {
+ bfa_os_memset(&lp, 0, sizeof(struct bfa_plog_rec_s));
+
+ ints[0] = tmp_int[0];
+ ints[1] = tmp_int[1];
+ ints[2] = tmp_int[4];
+ ints[3] = pld_w0;
+
+ bfa_plog_intarr(plog, mid, event, misc, ints, 4);
+ }
+}
+
+void
+bfa_plog_clear(struct bfa_plog_s *plog)
+{
+ plog->head = plog->tail = 0;
+}
+
+void
+bfa_plog_enable(struct bfa_plog_s *plog)
+{
+ plog->plog_enabled = 1;
+}
+
+void
+bfa_plog_disable(struct bfa_plog_s *plog)
+{
+ plog->plog_enabled = 0;
+}
+
+bfa_boolean_t
+bfa_plog_get_setting(struct bfa_plog_s *plog)
+{
+ return (bfa_boolean_t)plog->plog_enabled;
+}
diff --git a/drivers/scsi/bfa/rport.c b/drivers/scsi/bfa/rport.c
new file mode 100644
index 000000000000..9cf58bb138dc
--- /dev/null
+++ b/drivers/scsi/bfa/rport.c
@@ -0,0 +1,2618 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * rport.c Remote port implementation.
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcbuild.h"
+#include "fcs_vport.h"
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_fcpim.h"
+#include "fcs_fcptm.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs.h"
+#include <fcb/bfa_fcb_rport.h>
+#include <aen/bfa_aen_rport.h>
+
+BFA_TRC_FILE(FCS, RPORT);
+
+#define BFA_FCS_RPORT_MAX_RETRIES (5)
+
+/* In millisecs */
+static u32 bfa_fcs_rport_del_timeout =
+ BFA_FCS_RPORT_DEF_DEL_TIMEOUT * 1000;
+
+/*
+ * forward declarations
+ */
+static struct bfa_fcs_rport_s *bfa_fcs_rport_alloc(struct bfa_fcs_port_s *port,
+ wwn_t pwwn, u32 rpid);
+static void bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport,
+ struct fc_logi_s *plogi);
+static void bfa_fcs_rport_fc4_pause(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_fc4_resume(struct bfa_fcs_rport_s *rport);
+static void bfa_fcs_rport_timeout(void *arg);
+static void bfa_fcs_rport_send_plogi(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rport_send_plogiacc(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rport_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);
+static void bfa_fcs_rport_send_adisc(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rport_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);
+static void bfa_fcs_rport_send_gidpn(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rport_gidpn_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 void bfa_fcs_rport_send_logo(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rport_send_logo_acc(void *rport_cbarg);
+static void bfa_fcs_rport_process_prli(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u16 len);
+static void bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u8 reason_code,
+ u8 reason_code_expl);
+static void bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u16 len);
+/**
+ * fcs_rport_sm FCS rport state machine events
+ */
+
+enum rport_event {
+ RPSM_EVENT_PLOGI_SEND = 1, /* new rport; start with PLOGI */
+ RPSM_EVENT_PLOGI_RCVD = 2, /* Inbound PLOGI from remote port */
+ RPSM_EVENT_PLOGI_COMP = 3, /* PLOGI completed to rport */
+ RPSM_EVENT_LOGO_RCVD = 4, /* LOGO from remote device */
+ RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */
+ RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */
+ RPSM_EVENT_DELETE = 7, /* RPORT delete request */
+ RPSM_EVENT_SCN = 8, /* state change notification */
+ RPSM_EVENT_ACCEPTED = 9,/* Good response from remote device */
+ RPSM_EVENT_FAILED = 10, /* Request to rport failed. */
+ RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */
+ RPSM_EVENT_HCB_ONLINE = 12, /* BFA rport online callback */
+ RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */
+ RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */
+ RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */
+ RPSM_EVENT_ADDRESS_DISC = 16 /* Need to Discover rport's PID */
+};
+
+static void bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+static void bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
+ enum rport_event event);
+
+static struct bfa_sm_table_s rport_sm_table[] = {
+ {BFA_SM(bfa_fcs_rport_sm_uninit), BFA_RPORT_UNINIT},
+ {BFA_SM(bfa_fcs_rport_sm_plogi_sending), BFA_RPORT_PLOGI},
+ {BFA_SM(bfa_fcs_rport_sm_plogiacc_sending), BFA_RPORT_ONLINE},
+ {BFA_SM(bfa_fcs_rport_sm_plogi_retry), BFA_RPORT_PLOGI_RETRY},
+ {BFA_SM(bfa_fcs_rport_sm_plogi), BFA_RPORT_PLOGI},
+ {BFA_SM(bfa_fcs_rport_sm_hal_online), BFA_RPORT_ONLINE},
+ {BFA_SM(bfa_fcs_rport_sm_online), BFA_RPORT_ONLINE},
+ {BFA_SM(bfa_fcs_rport_sm_nsquery_sending), BFA_RPORT_NSQUERY},
+ {BFA_SM(bfa_fcs_rport_sm_nsquery), BFA_RPORT_NSQUERY},
+ {BFA_SM(bfa_fcs_rport_sm_adisc_sending), BFA_RPORT_ADISC},
+ {BFA_SM(bfa_fcs_rport_sm_adisc), BFA_RPORT_ADISC},
+ {BFA_SM(bfa_fcs_rport_sm_fc4_logorcv), BFA_RPORT_LOGORCV},
+ {BFA_SM(bfa_fcs_rport_sm_fc4_logosend), BFA_RPORT_LOGO},
+ {BFA_SM(bfa_fcs_rport_sm_fc4_offline), BFA_RPORT_OFFLINE},
+ {BFA_SM(bfa_fcs_rport_sm_hcb_offline), BFA_RPORT_OFFLINE},
+ {BFA_SM(bfa_fcs_rport_sm_hcb_logorcv), BFA_RPORT_LOGORCV},
+ {BFA_SM(bfa_fcs_rport_sm_hcb_logosend), BFA_RPORT_LOGO},
+ {BFA_SM(bfa_fcs_rport_sm_logo_sending), BFA_RPORT_LOGO},
+ {BFA_SM(bfa_fcs_rport_sm_offline), BFA_RPORT_OFFLINE},
+ {BFA_SM(bfa_fcs_rport_sm_nsdisc_sending), BFA_RPORT_NSDISC},
+ {BFA_SM(bfa_fcs_rport_sm_nsdisc_retry), BFA_RPORT_NSDISC},
+ {BFA_SM(bfa_fcs_rport_sm_nsdisc_sent), BFA_RPORT_NSDISC},
+};
+
+/**
+ * Beginning state.
+ */
+static void
+bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_PLOGI_SEND:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending);
+ rport->plogi_retries = 0;
+ bfa_fcs_rport_send_plogi(rport, NULL);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ case RPSM_EVENT_ADDRESS_DISC:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * PLOGI is being sent.
+ */
+static void
+bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_SCN:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * PLOGI is being sent.
+ */
+static void
+bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * Ignore, SCN is possibly online notification.
+ */
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_HCB_OFFLINE:
+ /**
+ * Ignore BFA callback, on a PLOGI receive we call bfa offline.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * PLOGI is sent.
+ */
+static void
+bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_SCN:
+ bfa_timer_stop(&rport->timer);
+ /*
+ * !! fall through !!
+ */
+
+ case RPSM_EVENT_TIMEOUT:
+ rport->plogi_retries++;
+ if (rport->plogi_retries < BFA_FCS_RPORT_MAX_RETRIES) {
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending);
+ bfa_fcs_rport_send_plogi(rport, NULL);
+ } else {
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ }
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_timer_stop(&rport->timer);
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_stop(&rport->timer);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * PLOGI is sent.
+ */
+static void
+bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_ACCEPTED:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ rport->plogi_retries = 0;
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_fcs_rport_send_logo_acc(rport);
+ bfa_fcxp_discard(rport->fcxp);
+ /*
+ * !! fall through !!
+ */
+ case RPSM_EVENT_FAILED:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_retry);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * Ignore SCN - wait for PLOGI response.
+ */
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * PLOGI is complete. Awaiting BFA rport online callback. FC-4s
+ * are offline.
+ */
+static void
+bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_HCB_ONLINE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_online);
+ bfa_fcs_rport_online_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_rport_offline(rport->bfa_rport);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * @todo
+ * Ignore SCN - PLOGI just completed, FC-4 login should detect
+ * device failures.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is ONLINE. FC-4s active.
+ */
+static void
+bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_SCN:
+ /**
+ * Pause FC-4 activity till rport is authenticated.
+ * In switched fabrics, check presence of device in nameserver
+ * first.
+ */
+ bfa_fcs_rport_fc4_pause(rport);
+
+ if (bfa_fcs_fabric_is_switched(rport->port->fabric)) {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsquery_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ } else {
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_sending);
+ bfa_fcs_rport_send_adisc(rport, NULL);
+ }
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ case RPSM_EVENT_LOGO_IMP:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * An SCN event is received in ONLINE state. NS query is being sent
+ * prior to ADISC authentication with rport. FC-4s are paused.
+ */
+static void
+bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsquery);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * ignore SCN, wait for response to query itself
+ */
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * An SCN event is received in ONLINE state. NS query is sent to rport.
+ * FC-4s are paused.
+ */
+static void
+bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_ACCEPTED:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_sending);
+ bfa_fcs_rport_send_adisc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_FAILED:
+ rport->ns_retries++;
+ if (rport->ns_retries < BFA_FCS_RPORT_MAX_RETRIES) {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsquery_sending);
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ } else {
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcs_rport_offline_action(rport);
+ }
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ case RPSM_EVENT_PLOGI_RCVD:
+ case RPSM_EVENT_LOGO_IMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * An SCN event is received in ONLINE state. ADISC is being sent for
+ * authenticating with rport. FC-4s are paused.
+ */
+static void
+bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * An SCN event is received in ONLINE state. ADISC is to rport.
+ * FC-4s are paused.
+ */
+static void
+bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_ACCEPTED:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_online);
+ bfa_fcs_rport_fc4_resume(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ /**
+ * Too complex to cleanup FC-4 & rport and then acc to PLOGI.
+ * At least go offline when a PLOGI is received.
+ */
+ bfa_fcxp_discard(rport->fcxp);
+ /*
+ * !!! fall through !!!
+ */
+
+ case RPSM_EVENT_FAILED:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * already processing RSCN
+ */
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_offline_action(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport has sent LOGO. Awaiting FC-4 offline completion callback.
+ */
+static void
+bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FC4_OFFLINE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * LOGO needs to be sent to rport. Awaiting FC-4 offline completion
+ * callback.
+ */
+static void
+bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FC4_OFFLINE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is going offline. Awaiting FC-4 offline completion callback.
+ */
+static void
+bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FC4_OFFLINE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline);
+ bfa_rport_offline(rport->bfa_rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_LOGO_IMP:
+ case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ /**
+ * rport is already going offline.
+ * SCN - ignore and wait till transitioning to offline state
+ */
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is offline. FC-4s are offline. Awaiting BFA rport offline
+ * callback.
+ */
+static void
+bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_HCB_OFFLINE:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ if (bfa_fcs_port_is_online(rport->port)) {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ } else {
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ }
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_LOGO_RCVD:
+ /**
+ * Ignore, already offline.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is offline. FC-4s are offline. Awaiting BFA rport offline
+ * callback to send LOGO accept.
+ */
+static void
+bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_HCB_OFFLINE:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ if (rport->pid)
+ bfa_fcs_rport_send_logo_acc(rport);
+ /*
+ * If the lport is online and if the rport is not a well known
+ * address port, we try to re-discover the r-port.
+ */
+ if (bfa_fcs_port_is_online(rport->port)
+ && (!BFA_FCS_PID_IS_WKA(rport->pid))) {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ } else {
+ /*
+ * if it is not a well known address, reset the pid to
+ *
+ */
+ if (!BFA_FCS_PID_IS_WKA(rport->pid))
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ }
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ /**
+ * Ignore - already processing a LOGO.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is being deleted. FC-4s are offline. Awaiting BFA rport offline
+ * callback to send LOGO.
+ */
+static void
+bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_HCB_OFFLINE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_logo_sending);
+ bfa_fcs_rport_send_logo(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is being deleted. FC-4s are offline. LOGO is being sent.
+ */
+static void
+bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ /*
+ * Once LOGO is sent, we donot wait for the response
+ */
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport is offline. FC-4s are offline. BFA rport is offline.
+ * Timer active to delete stale rport.
+ */
+static void
+bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_TIMEOUT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ bfa_timer_stop(&rport->timer);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_LOGO_IMP:
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_SEND:
+ bfa_timer_stop(&rport->timer);
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending);
+ rport->plogi_retries = 0;
+ bfa_fcs_rport_send_plogi(rport, NULL);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport address has changed. Nameserver discovery request is being sent.
+ */
+static void
+bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sent);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_LOGO_RCVD:
+ case RPSM_EVENT_PLOGI_SEND:
+ break;
+
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ rport->ns_retries = 0; /* reset the retry count */
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Nameserver discovery failed. Waiting for timeout to retry.
+ */
+static void
+bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_TIMEOUT:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_SCN:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending);
+ bfa_timer_stop(&rport->timer);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_stop(&rport->timer);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ bfa_fcs_rport_send_logo_acc(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_timer_stop(&rport->timer);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Rport address has changed. Nameserver discovery request is sent.
+ */
+static void
+bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport,
+ enum rport_event event)
+{
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPSM_EVENT_ACCEPTED:
+ case RPSM_EVENT_ADDRESS_CHANGE:
+ if (rport->pid) {
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending);
+ bfa_fcs_rport_send_plogi(rport, NULL);
+ } else {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsdisc_sending);
+ rport->ns_retries = 0;
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ }
+ break;
+
+ case RPSM_EVENT_FAILED:
+ rport->ns_retries++;
+ if (rport->ns_retries < BFA_FCS_RPORT_MAX_RETRIES) {
+ bfa_sm_set_state(rport,
+ bfa_fcs_rport_sm_nsdisc_sending);
+ bfa_fcs_rport_send_gidpn(rport, NULL);
+ } else {
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ };
+ break;
+
+ case RPSM_EVENT_DELETE:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_free(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_RCVD:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_send_plogiacc(rport, NULL);
+ break;
+
+ case RPSM_EVENT_LOGO_IMP:
+ rport->pid = 0;
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_timer_start(rport->fcs->bfa, &rport->timer,
+ bfa_fcs_rport_timeout, rport,
+ bfa_fcs_rport_del_timeout);
+ break;
+
+ case RPSM_EVENT_SCN:
+ /**
+ * ignore, wait for NS query response
+ */
+ break;
+
+ case RPSM_EVENT_LOGO_RCVD:
+ /**
+ * Not logged-in yet. Accept LOGO.
+ */
+ bfa_fcs_rport_send_logo_acc(rport);
+ break;
+
+ case RPSM_EVENT_PLOGI_COMP:
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online);
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_fcs_rport_hal_online(rport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * fcs_rport_private FCS RPORT provate functions
+ */
+
+static void
+bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe,
+ bfa_fcs_rport_send_plogi, rport);
+ return;
+ }
+ rport->fcxp = fcxp;
+
+ len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ 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_rport_plogi_response,
+ (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ rport->stats.plogis++;
+ bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_rport_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)
+{
+ struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+ struct fc_logi_s *plogi_rsp;
+ struct fc_ls_rjt_s *ls_rjt;
+ struct bfa_fcs_rport_s *twin;
+ struct list_head *qe;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(rport->fcs, req_status);
+ rport->stats.plogi_failed++;
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+ return;
+ }
+
+ plogi_rsp = (struct fc_logi_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ /**
+ * Check for failure first.
+ */
+ if (plogi_rsp->els_cmd.els_code != FC_ELS_ACC) {
+ ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ bfa_trc(rport->fcs, ls_rjt->reason_code);
+ bfa_trc(rport->fcs, ls_rjt->reason_code_expl);
+
+ rport->stats.plogi_rejects++;
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+ return;
+ }
+
+ /**
+ * PLOGI is complete. Make sure this device is not one of the known
+ * device with a new FC port address.
+ */
+ list_for_each(qe, &rport->port->rport_q) {
+ twin = (struct bfa_fcs_rport_s *)qe;
+ if (twin == rport)
+ continue;
+ if (!rport->pwwn && (plogi_rsp->port_name == twin->pwwn)) {
+ bfa_trc(rport->fcs, twin->pid);
+ bfa_trc(rport->fcs, rport->pid);
+
+ /*
+ * Update plogi stats in twin
+ */
+ twin->stats.plogis += rport->stats.plogis;
+ twin->stats.plogi_rejects += rport->stats.plogi_rejects;
+ twin->stats.plogi_timeouts +=
+ rport->stats.plogi_timeouts;
+ twin->stats.plogi_failed += rport->stats.plogi_failed;
+ twin->stats.plogi_rcvd += rport->stats.plogi_rcvd;
+ twin->stats.plogi_accs++;
+
+ bfa_fcs_rport_delete(rport);
+
+ bfa_fcs_rport_update(twin, plogi_rsp);
+ twin->pid = rsp_fchs->s_id;
+ bfa_sm_send_event(twin, RPSM_EVENT_PLOGI_COMP);
+ return;
+ }
+ }
+
+ /**
+ * Normal login path -- no evil twins.
+ */
+ rport->stats.plogi_accs++;
+ bfa_fcs_rport_update(rport, plogi_rsp);
+ bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED);
+}
+
+static void
+bfa_fcs_rport_send_plogiacc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->reply_oxid);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe,
+ bfa_fcs_rport_send_plogiacc, rport);
+ return;
+ }
+ rport->fcxp = fcxp;
+
+ len = fc_plogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ bfa_fcs_port_get_fcid(port), rport->reply_oxid,
+ 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, NULL, NULL, FC_MAX_PDUSZ, 0);
+
+ bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_rport_send_adisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe,
+ bfa_fcs_rport_send_adisc, rport);
+ return;
+ }
+ rport->fcxp = fcxp;
+
+ len = fc_adisc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ 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_rport_adisc_response,
+ rport, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ rport->stats.adisc_sent++;
+ bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_rport_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_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+ void *pld = bfa_fcxp_get_rspbuf(fcxp);
+ struct fc_ls_rjt_s *ls_rjt;
+
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(rport->fcs, req_status);
+ rport->stats.adisc_failed++;
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+ return;
+ }
+
+ if (fc_adisc_rsp_parse((struct fc_adisc_s *)pld, rsp_len, rport->pwwn,
+ rport->nwwn) == FC_PARSE_OK) {
+ rport->stats.adisc_accs++;
+ bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED);
+ return;
+ }
+
+ rport->stats.adisc_rejects++;
+ ls_rjt = pld;
+ bfa_trc(rport->fcs, ls_rjt->els_cmd.els_code);
+ bfa_trc(rport->fcs, ls_rjt->reason_code);
+ bfa_trc(rport->fcs, ls_rjt->reason_code_expl);
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+}
+
+static void
+bfa_fcs_rport_send_gidpn(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ int len;
+
+ bfa_trc(rport->fcs, rport->pid);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe,
+ bfa_fcs_rport_send_gidpn, rport);
+ return;
+ }
+ rport->fcxp = fcxp;
+
+ len = fc_gidpn_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_fcs_port_get_fcid(port), 0, rport->pwwn);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_rport_gidpn_response,
+ (void *)rport, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
+}
+
+static void
+bfa_fcs_rport_gidpn_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_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+ struct bfa_fcs_rport_s *twin;
+ struct list_head *qe;
+ struct ct_hdr_s *cthdr;
+ struct fcgs_gidpn_resp_s *gidpn_rsp;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+
+ cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp);
+ cthdr->cmd_rsp_code = bfa_os_ntohs(cthdr->cmd_rsp_code);
+
+ if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) {
+ /*
+ * Check if the pid is the same as before.
+ */
+ gidpn_rsp = (struct fcgs_gidpn_resp_s *) (cthdr + 1);
+
+ if (gidpn_rsp->dap == rport->pid) {
+ /*
+ * Device is online
+ */
+ bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED);
+ } else {
+ /*
+ * Device's PID has changed. We need to cleanup and
+ * re-login. If there is another device with the the
+ * newly discovered pid, send an scn notice so that its
+ * new pid can be discovered.
+ */
+ list_for_each(qe, &rport->port->rport_q) {
+ twin = (struct bfa_fcs_rport_s *)qe;
+ if (twin == rport)
+ continue;
+ if (gidpn_rsp->dap == twin->pid) {
+ bfa_trc(rport->fcs, twin->pid);
+ bfa_trc(rport->fcs, rport->pid);
+
+ twin->pid = 0;
+ bfa_sm_send_event(twin,
+ RPSM_EVENT_ADDRESS_CHANGE);
+ }
+ }
+ rport->pid = gidpn_rsp->dap;
+ bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_CHANGE);
+ }
+ return;
+ }
+
+ /*
+ * Reject Response
+ */
+ switch (cthdr->reason_code) {
+ case CT_RSN_LOGICAL_BUSY:
+ /*
+ * Need to retry
+ */
+ bfa_sm_send_event(rport, RPSM_EVENT_TIMEOUT);
+ break;
+
+ case CT_RSN_UNABLE_TO_PERF:
+ /*
+ * device doesn't exist : Start timer to cleanup this later.
+ */
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+ break;
+
+ default:
+ bfa_sm_send_event(rport, RPSM_EVENT_FAILED);
+ break;
+ }
+}
+
+/**
+ * Called to send a logout to the rport.
+ */
+static void
+bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ u16 len;
+
+ bfa_trc(rport->fcs, rport->pid);
+
+ port = rport->port;
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe,
+ bfa_fcs_rport_send_logo, rport);
+ return;
+ }
+ rport->fcxp = fcxp;
+
+ len = fc_logo_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ bfa_fcs_port_get_fcid(port), 0,
+ bfa_fcs_port_get_pwwn(port));
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, NULL, rport, FC_MAX_PDUSZ,
+ FC_ED_TOV);
+
+ rport->stats.logos++;
+ bfa_fcxp_discard(rport->fcxp);
+ bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT);
+}
+
+/**
+ * Send ACC for a LOGO received.
+ */
+static void
+bfa_fcs_rport_send_logo_acc(void *rport_cbarg)
+{
+ struct bfa_fcs_rport_s *rport = rport_cbarg;
+ struct bfa_fcs_port_s *port;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ u16 len;
+
+ bfa_trc(rport->fcs, rport->pid);
+
+ port = rport->port;
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ rport->stats.logo_rcvd++;
+ len = fc_logo_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ bfa_fcs_port_get_fcid(port), rport->reply_oxid);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0);
+}
+
+/**
+ * This routine will be called by bfa_timer on timer timeouts.
+ *
+ * param[in] rport - pointer to bfa_fcs_port_ns_t.
+ * param[out] rport_status - pointer to return vport status in
+ *
+ * return
+ * void
+ *
+* Special Considerations:
+ *
+ * note
+ */
+static void
+bfa_fcs_rport_timeout(void *arg)
+{
+ struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)arg;
+
+ rport->stats.plogi_timeouts++;
+ bfa_sm_send_event(rport, RPSM_EVENT_TIMEOUT);
+}
+
+static void
+bfa_fcs_rport_process_prli(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u16 len)
+{
+ struct bfa_fcxp_s *fcxp;
+ struct fchs_s fchs;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fc_prli_s *prli;
+
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ bfa_trc(port->fcs, rx_fchs->d_id);
+
+ rport->stats.prli_rcvd++;
+
+ if (BFA_FCS_VPORT_IS_TARGET_MODE(port)) {
+ /*
+ * Target Mode : Let the fcptm handle it
+ */
+ bfa_fcs_tin_rx_prli(rport->tin, rx_fchs, len);
+ return;
+ }
+
+ /*
+ * We are either in Initiator or ipfc Mode
+ */
+ prli = (struct fc_prli_s *) (rx_fchs + 1);
+
+ if (prli->parampage.servparams.initiator) {
+ bfa_trc(rport->fcs, prli->parampage.type);
+ rport->scsi_function = BFA_RPORT_INITIATOR;
+ bfa_fcs_itnim_is_initiator(rport->itnim);
+ } else {
+ /*
+ * @todo: PRLI from a target ?
+ */
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ rport->scsi_function = BFA_RPORT_TARGET;
+ }
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_prli_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
+ port->port_cfg.roles);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0);
+}
+
+static void
+bfa_fcs_rport_process_rpsc(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u16 len)
+{
+ struct bfa_fcxp_s *fcxp;
+ struct fchs_s fchs;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fc_rpsc_speed_info_s speeds;
+ struct bfa_pport_attr_s pport_attr;
+
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ bfa_trc(port->fcs, rx_fchs->d_id);
+
+ rport->stats.rpsc_rcvd++;
+ speeds.port_speed_cap =
+ RPSC_SPEED_CAP_1G | RPSC_SPEED_CAP_2G | RPSC_SPEED_CAP_4G |
+ RPSC_SPEED_CAP_8G;
+
+ /*
+ * get curent speed from pport attributes from BFA
+ */
+ bfa_pport_get_attr(port->fcs->bfa, &pport_attr);
+
+ speeds.port_op_speed = fc_bfa_speed_to_rpsc_operspeed(pport_attr.speed);
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_rpsc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
+ &speeds);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0);
+}
+
+static void
+bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport,
+ struct fchs_s *rx_fchs, u16 len)
+{
+ struct bfa_fcxp_s *fcxp;
+ struct fchs_s fchs;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fc_adisc_s *adisc;
+
+ bfa_trc(port->fcs, rx_fchs->s_id);
+ bfa_trc(port->fcs, rx_fchs->d_id);
+
+ rport->stats.adisc_rcvd++;
+
+ if (BFA_FCS_VPORT_IS_TARGET_MODE(port)) {
+ /*
+ * @todo : Target Mode handling
+ */
+ bfa_trc(port->fcs, rx_fchs->d_id);
+ bfa_assert(0);
+ return;
+ }
+
+ adisc = (struct fc_adisc_s *) (rx_fchs + 1);
+
+ /*
+ * Accept if the itnim for this rport is online. Else reject the ADISC
+ */
+ if (bfa_fcs_itnim_get_online_state(rport->itnim) == BFA_STATUS_OK) {
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_adisc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port),
+ rx_fchs->ox_id, 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, NULL, NULL,
+ FC_MAX_PDUSZ, 0);
+ } else {
+ rport->stats.adisc_rejected++;
+ bfa_fcs_rport_send_ls_rjt(rport, rx_fchs,
+ FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD,
+ FC_LS_RJT_EXP_LOGIN_REQUIRED);
+ }
+
+}
+
+static void
+bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+ struct bfa_rport_info_s rport_info;
+
+ rport_info.pid = rport->pid;
+ rport_info.local_pid = port->pid;
+ rport_info.lp_tag = port->lp_tag;
+ rport_info.vf_id = port->fabric->vf_id;
+ rport_info.vf_en = port->fabric->is_vf;
+ rport_info.fc_class = rport->fc_cos;
+ rport_info.cisc = rport->cisc;
+ rport_info.max_frmsz = rport->maxfrsize;
+ bfa_rport_online(rport->bfa_rport, &rport_info);
+}
+
+static void
+bfa_fcs_rport_fc4_pause(struct bfa_fcs_rport_s *rport)
+{
+ if (bfa_fcs_port_is_initiator(rport->port))
+ bfa_fcs_itnim_pause(rport->itnim);
+
+ if (bfa_fcs_port_is_target(rport->port))
+ bfa_fcs_tin_pause(rport->tin);
+}
+
+static void
+bfa_fcs_rport_fc4_resume(struct bfa_fcs_rport_s *rport)
+{
+ if (bfa_fcs_port_is_initiator(rport->port))
+ bfa_fcs_itnim_resume(rport->itnim);
+
+ if (bfa_fcs_port_is_target(rport->port))
+ bfa_fcs_tin_resume(rport->tin);
+}
+
+static struct bfa_fcs_rport_s *
+bfa_fcs_rport_alloc(struct bfa_fcs_port_s *port, wwn_t pwwn, u32 rpid)
+{
+ struct bfa_fcs_s *fcs = port->fcs;
+ struct bfa_fcs_rport_s *rport;
+ struct bfad_rport_s *rport_drv;
+
+ /**
+ * allocate rport
+ */
+ if (bfa_fcb_rport_alloc(fcs->bfad, &rport, &rport_drv)
+ != BFA_STATUS_OK) {
+ bfa_trc(fcs, rpid);
+ return NULL;
+ }
+
+ /*
+ * Initialize r-port
+ */
+ rport->port = port;
+ rport->fcs = fcs;
+ rport->rp_drv = rport_drv;
+ rport->pid = rpid;
+ rport->pwwn = pwwn;
+
+ /**
+ * allocate BFA rport
+ */
+ rport->bfa_rport = bfa_rport_create(port->fcs->bfa, rport);
+ if (!rport->bfa_rport) {
+ bfa_trc(fcs, rpid);
+ kfree(rport_drv);
+ return NULL;
+ }
+
+ /**
+ * allocate FC-4s
+ */
+ bfa_assert(bfa_fcs_port_is_initiator(port) ^
+ bfa_fcs_port_is_target(port));
+
+ if (bfa_fcs_port_is_initiator(port)) {
+ rport->itnim = bfa_fcs_itnim_create(rport);
+ if (!rport->itnim) {
+ bfa_trc(fcs, rpid);
+ bfa_rport_delete(rport->bfa_rport);
+ kfree(rport_drv);
+ return NULL;
+ }
+ }
+
+ if (bfa_fcs_port_is_target(port)) {
+ rport->tin = bfa_fcs_tin_create(rport);
+ if (!rport->tin) {
+ bfa_trc(fcs, rpid);
+ bfa_rport_delete(rport->bfa_rport);
+ kfree(rport_drv);
+ return NULL;
+ }
+ }
+
+ bfa_fcs_port_add_rport(port, rport);
+
+ bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit);
+
+ /*
+ * Initialize the Rport Features(RPF) Sub Module
+ */
+ if (!BFA_FCS_PID_IS_WKA(rport->pid))
+ bfa_fcs_rpf_init(rport);
+
+ return rport;
+}
+
+
+static void
+bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+
+ /**
+ * - delete FC-4s
+ * - delete BFA rport
+ * - remove from queue of rports
+ */
+ if (bfa_fcs_port_is_initiator(port))
+ bfa_fcs_itnim_delete(rport->itnim);
+
+ if (bfa_fcs_port_is_target(port))
+ bfa_fcs_tin_delete(rport->tin);
+
+ bfa_rport_delete(rport->bfa_rport);
+ bfa_fcs_port_del_rport(port, rport);
+ kfree(rport->rp_drv);
+}
+
+static void
+bfa_fcs_rport_aen_post(struct bfa_fcs_rport_s *rport,
+ enum bfa_rport_aen_event event,
+ struct bfa_rport_aen_data_s *data)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = rport->fcs->logm;
+ wwn_t lpwwn = bfa_fcs_port_get_pwwn(rport->port);
+ wwn_t rpwwn = rport->pwwn;
+ char lpwwn_ptr[BFA_STRING_32];
+ char rpwwn_ptr[BFA_STRING_32];
+ char *prio_str[] = { "unknown", "high", "medium", "low" };
+
+ wwn2str(lpwwn_ptr, lpwwn);
+ wwn2str(rpwwn_ptr, rpwwn);
+
+ switch (event) {
+ case BFA_RPORT_AEN_ONLINE:
+ bfa_log(logmod, BFA_AEN_RPORT_ONLINE, rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_RPORT_AEN_OFFLINE:
+ bfa_log(logmod, BFA_AEN_RPORT_OFFLINE, rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_RPORT_AEN_DISCONNECT:
+ bfa_log(logmod, BFA_AEN_RPORT_DISCONNECT, rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_RPORT_AEN_QOS_PRIO:
+ aen_data.rport.priv.qos = data->priv.qos;
+ bfa_log(logmod, BFA_AEN_RPORT_QOS_PRIO,
+ prio_str[aen_data.rport.priv.qos.qos_priority],
+ rpwwn_ptr, lpwwn_ptr);
+ break;
+ case BFA_RPORT_AEN_QOS_FLOWID:
+ aen_data.rport.priv.qos = data->priv.qos;
+ bfa_log(logmod, BFA_AEN_RPORT_QOS_FLOWID,
+ aen_data.rport.priv.qos.qos_flow_id, rpwwn_ptr,
+ lpwwn_ptr);
+ break;
+ default:
+ break;
+ }
+
+ aen_data.rport.vf_id = rport->port->fabric->vf_id;
+ aen_data.rport.ppwwn =
+ bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(rport->fcs));
+ aen_data.rport.lpwwn = lpwwn;
+ aen_data.rport.rpwwn = rpwwn;
+}
+
+static void
+bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+
+ rport->stats.onlines++;
+
+ if (bfa_fcs_port_is_initiator(port)) {
+ bfa_fcs_itnim_rport_online(rport->itnim);
+ if (!BFA_FCS_PID_IS_WKA(rport->pid))
+ bfa_fcs_rpf_rport_online(rport);
+ };
+
+ if (bfa_fcs_port_is_target(port))
+ bfa_fcs_tin_rport_online(rport->tin);
+
+ /*
+ * Don't post events for well known addresses
+ */
+ if (!BFA_FCS_PID_IS_WKA(rport->pid))
+ bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_ONLINE, NULL);
+}
+
+static void
+bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+
+ rport->stats.offlines++;
+
+ /*
+ * Don't post events for well known addresses
+ */
+ if (!BFA_FCS_PID_IS_WKA(rport->pid)) {
+ if (bfa_fcs_port_is_online(rport->port) == BFA_TRUE) {
+ bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_DISCONNECT,
+ NULL);
+ } else {
+ bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_OFFLINE,
+ NULL);
+ }
+ }
+
+ if (bfa_fcs_port_is_initiator(port)) {
+ bfa_fcs_itnim_rport_offline(rport->itnim);
+ if (!BFA_FCS_PID_IS_WKA(rport->pid))
+ bfa_fcs_rpf_rport_offline(rport);
+ }
+
+ if (bfa_fcs_port_is_target(port))
+ bfa_fcs_tin_rport_offline(rport->tin);
+}
+
+/**
+ * Update rport parameters from PLOGI or PLOGI accept.
+ */
+static void
+bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+
+ /**
+ * - port name
+ * - node name
+ */
+ rport->pwwn = plogi->port_name;
+ rport->nwwn = plogi->node_name;
+
+ /**
+ * - class of service
+ */
+ rport->fc_cos = 0;
+ if (plogi->class3.class_valid)
+ rport->fc_cos = FC_CLASS_3;
+
+ if (plogi->class2.class_valid)
+ rport->fc_cos |= FC_CLASS_2;
+
+ /**
+ * - CISC
+ * - MAX receive frame size
+ */
+ rport->cisc = plogi->csp.cisc;
+ rport->maxfrsize = bfa_os_ntohs(plogi->class3.rxsz);
+
+ bfa_trc(port->fcs, bfa_os_ntohs(plogi->csp.bbcred));
+ bfa_trc(port->fcs, port->fabric->bb_credit);
+ /**
+ * Direct Attach P2P mode :
+ * This is to handle a bug (233476) in IBM targets in Direct Attach
+ * Mode. Basically, in FLOGI Accept the target would have erroneously
+ * set the BB Credit to the value used in the FLOGI sent by the HBA.
+ * It uses the correct value (its own BB credit) in PLOGI.
+ */
+ if ((!bfa_fcs_fabric_is_switched(port->fabric))
+ && (bfa_os_ntohs(plogi->csp.bbcred) < port->fabric->bb_credit)) {
+
+ bfa_trc(port->fcs, bfa_os_ntohs(plogi->csp.bbcred));
+ bfa_trc(port->fcs, port->fabric->bb_credit);
+
+ port->fabric->bb_credit = bfa_os_ntohs(plogi->csp.bbcred);
+ bfa_pport_set_tx_bbcredit(port->fcs->bfa,
+ port->fabric->bb_credit);
+ }
+
+}
+
+/**
+ * Called to handle LOGO received from an existing remote port.
+ */
+static void
+bfa_fcs_rport_process_logo(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs)
+{
+ rport->reply_oxid = fchs->ox_id;
+ bfa_trc(rport->fcs, rport->reply_oxid);
+
+ rport->stats.logo_rcvd++;
+ bfa_sm_send_event(rport, RPSM_EVENT_LOGO_RCVD);
+}
+
+
+
+/**
+ * fcs_rport_public FCS rport public interfaces
+ */
+
+/**
+ * Called by bport/vport to create a remote port instance for a discovered
+ * remote device.
+ *
+ * @param[in] port - base port or vport
+ * @param[in] rpid - remote port ID
+ *
+ * @return None
+ */
+struct bfa_fcs_rport_s *
+bfa_fcs_rport_create(struct bfa_fcs_port_s *port, u32 rpid)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ bfa_trc(port->fcs, rpid);
+ rport = bfa_fcs_rport_alloc(port, WWN_NULL, rpid);
+ if (!rport)
+ return NULL;
+
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND);
+ return rport;
+}
+
+/**
+ * Called to create a rport for which only the wwn is known.
+ *
+ * @param[in] port - base port
+ * @param[in] rpwwn - remote port wwn
+ *
+ * @return None
+ */
+struct bfa_fcs_rport_s *
+bfa_fcs_rport_create_by_wwn(struct bfa_fcs_port_s *port, wwn_t rpwwn)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ bfa_trc(port->fcs, rpwwn);
+ rport = bfa_fcs_rport_alloc(port, rpwwn, 0);
+ if (!rport)
+ return NULL;
+
+ bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_DISC);
+ return rport;
+}
+
+/**
+ * Called by bport in private loop topology to indicate that a
+ * rport has been discovered and plogi has been completed.
+ *
+ * @param[in] port - base port or vport
+ * @param[in] rpid - remote port ID
+ */
+void
+bfa_fcs_rport_start(struct bfa_fcs_port_s *port, struct fchs_s *fchs,
+ struct fc_logi_s *plogi)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ rport = bfa_fcs_rport_alloc(port, WWN_NULL, fchs->s_id);
+ if (!rport)
+ return;
+
+ bfa_fcs_rport_update(rport, plogi);
+
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_COMP);
+}
+
+/**
+ * Called by bport/vport to handle PLOGI received from a new remote port.
+ * If an existing rport does a plogi, it will be handled separately.
+ */
+void
+bfa_fcs_rport_plogi_create(struct bfa_fcs_port_s *port, struct fchs_s *fchs,
+ struct fc_logi_s *plogi)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ rport = bfa_fcs_rport_alloc(port, plogi->port_name, fchs->s_id);
+ if (!rport)
+ return;
+
+ bfa_fcs_rport_update(rport, plogi);
+
+ rport->reply_oxid = fchs->ox_id;
+ bfa_trc(rport->fcs, rport->reply_oxid);
+
+ rport->stats.plogi_rcvd++;
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD);
+}
+
+static int
+wwn_compare(wwn_t wwn1, wwn_t wwn2)
+{
+ u8 *b1 = (u8 *) &wwn1;
+ u8 *b2 = (u8 *) &wwn2;
+ int i;
+
+ for (i = 0; i < sizeof(wwn_t); i++) {
+ if (b1[i] < b2[i])
+ return -1;
+ if (b1[i] > b2[i])
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * Called by bport/vport to handle PLOGI received from an existing
+ * remote port.
+ */
+void
+bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
+ struct fc_logi_s *plogi)
+{
+ /**
+ * @todo Handle P2P and initiator-initiator.
+ */
+
+ bfa_fcs_rport_update(rport, plogi);
+
+ rport->reply_oxid = rx_fchs->ox_id;
+ bfa_trc(rport->fcs, rport->reply_oxid);
+
+ /**
+ * In Switched fabric topology,
+ * PLOGI to each other. If our pwwn is smaller, ignore it,
+ * if it is not a well known address.
+ * If the link topology is N2N,
+ * this Plogi should be accepted.
+ */
+ if ((wwn_compare(rport->port->port_cfg.pwwn, rport->pwwn) == -1)
+ && (bfa_fcs_fabric_is_switched(rport->port->fabric))
+ && (!BFA_FCS_PID_IS_WKA(rport->pid))) {
+ bfa_trc(rport->fcs, rport->pid);
+ return;
+ }
+
+ rport->stats.plogi_rcvd++;
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD);
+}
+
+/**
+ * Called by bport/vport to delete a remote port instance.
+ *
+* Rport delete is called under the following conditions:
+ * - vport is deleted
+ * - vf is deleted
+ * - explicit request from OS to delete rport (vmware)
+ */
+void
+bfa_fcs_rport_delete(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_DELETE);
+}
+
+/**
+ * Called by bport/vport to when a target goes offline.
+ *
+ */
+void
+bfa_fcs_rport_offline(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
+}
+
+/**
+ * Called by bport in n2n when a target (attached port) becomes online.
+ *
+ */
+void
+bfa_fcs_rport_online(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND);
+}
+
+/**
+ * Called by bport/vport to notify SCN for the remote port
+ */
+void
+bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport)
+{
+
+ rport->stats.rscns++;
+ bfa_sm_send_event(rport, RPSM_EVENT_SCN);
+}
+
+/**
+ * Called by fcpim to notify that the ITN cleanup is done.
+ */
+void
+bfa_fcs_rport_itnim_ack(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE);
+}
+
+/**
+ * Called by fcptm to notify that the ITN cleanup is done.
+ */
+void
+bfa_fcs_rport_tin_ack(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_FC4_OFFLINE);
+}
+
+/**
+ * This routine BFA callback for bfa_rport_online() call.
+ *
+ * param[in] cb_arg - rport struct.
+ *
+ * return
+ * void
+ *
+* Special Considerations:
+ *
+ * note
+ */
+void
+bfa_cb_rport_online(void *cbarg)
+{
+
+ struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_sm_send_event(rport, RPSM_EVENT_HCB_ONLINE);
+}
+
+/**
+ * This routine BFA callback for bfa_rport_offline() call.
+ *
+ * param[in] rport -
+ *
+ * return
+ * void
+ *
+ * Special Considerations:
+ *
+ * note
+ */
+void
+bfa_cb_rport_offline(void *cbarg)
+{
+ struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_sm_send_event(rport, RPSM_EVENT_HCB_OFFLINE);
+}
+
+/**
+ * This routine is a static BFA callback when there is a QoS flow_id
+ * change notification
+ *
+ * @param[in] rport -
+ *
+ * @return void
+ *
+ * Special Considerations:
+ *
+ * @note
+ */
+void
+bfa_cb_rport_qos_scn_flowid(void *cbarg,
+ struct bfa_rport_qos_attr_s old_qos_attr,
+ struct bfa_rport_qos_attr_s new_qos_attr)
+{
+ struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+ struct bfa_rport_aen_data_s aen_data;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ aen_data.priv.qos = new_qos_attr;
+ bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_FLOWID, &aen_data);
+}
+
+/**
+ * This routine is a static BFA callback when there is a QoS priority
+ * change notification
+ *
+ * @param[in] rport -
+ *
+ * @return void
+ *
+ * Special Considerations:
+ *
+ * @note
+ */
+void
+bfa_cb_rport_qos_scn_prio(void *cbarg, struct bfa_rport_qos_attr_s old_qos_attr,
+ struct bfa_rport_qos_attr_s new_qos_attr)
+{
+ struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *)cbarg;
+ struct bfa_rport_aen_data_s aen_data;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ aen_data.priv.qos = new_qos_attr;
+ bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_PRIO, &aen_data);
+}
+
+/**
+ * Called to process any unsolicted frames from this remote port
+ */
+void
+bfa_fcs_rport_logo_imp(struct bfa_fcs_rport_s *rport)
+{
+ bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP);
+}
+
+/**
+ * Called to process any unsolicted frames from this remote port
+ */
+void
+bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs,
+ u16 len)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fc_els_cmd_s *els_cmd;
+
+ bfa_trc(rport->fcs, fchs->s_id);
+ bfa_trc(rport->fcs, fchs->d_id);
+ bfa_trc(rport->fcs, fchs->type);
+
+ if (fchs->type != FC_TYPE_ELS)
+ return;
+
+ els_cmd = (struct fc_els_cmd_s *) (fchs + 1);
+
+ bfa_trc(rport->fcs, els_cmd->els_code);
+
+ switch (els_cmd->els_code) {
+ case FC_ELS_LOGO:
+ bfa_fcs_rport_process_logo(rport, fchs);
+ break;
+
+ case FC_ELS_ADISC:
+ bfa_fcs_rport_process_adisc(rport, fchs, len);
+ break;
+
+ case FC_ELS_PRLO:
+ if (bfa_fcs_port_is_initiator(port))
+ bfa_fcs_fcpim_uf_recv(rport->itnim, fchs, len);
+
+ if (bfa_fcs_port_is_target(port))
+ bfa_fcs_fcptm_uf_recv(rport->tin, fchs, len);
+ break;
+
+ case FC_ELS_PRLI:
+ bfa_fcs_rport_process_prli(rport, fchs, len);
+ break;
+
+ case FC_ELS_RPSC:
+ bfa_fcs_rport_process_rpsc(rport, fchs, len);
+ break;
+
+ default:
+ bfa_fcs_rport_send_ls_rjt(rport, fchs,
+ FC_LS_RJT_RSN_CMD_NOT_SUPP,
+ FC_LS_RJT_EXP_NO_ADDL_INFO);
+ break;
+ }
+}
+
+/*
+ * Send a LS reject
+ */
+static void
+bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs,
+ u8 reason_code, u8 reason_code_expl)
+{
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ int len;
+
+ bfa_trc(rport->fcs, rx_fchs->s_id);
+
+ fcxp = bfa_fcs_fcxp_alloc(rport->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port), rx_fchs->ox_id,
+ reason_code, reason_code_expl);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0);
+}
+
+/**
+ * Module initialization
+ */
+void
+bfa_fcs_rport_modinit(struct bfa_fcs_s *fcs)
+{
+}
+
+/**
+ * Module cleanup
+ */
+void
+bfa_fcs_rport_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
+
+/**
+ * Return state of rport.
+ */
+int
+bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport)
+{
+ return bfa_sm_to_state(rport_sm_table, rport->sm);
+}
+
+/**
+ * Called by the Driver to set rport delete/ageout timeout
+ *
+ * param[in] rport timeout value in seconds.
+ *
+ * return None
+ */
+void
+bfa_fcs_rport_set_del_timeout(u8 rport_tmo)
+{
+ /*
+ * convert to Millisecs
+ */
+ if (rport_tmo > 0)
+ bfa_fcs_rport_del_timeout = rport_tmo * 1000;
+}
diff --git a/drivers/scsi/bfa/rport_api.c b/drivers/scsi/bfa/rport_api.c
new file mode 100644
index 000000000000..3dae1774181e
--- /dev/null
+++ b/drivers/scsi/bfa/rport_api.c
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_vport.h"
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_trcmod.h"
+
+BFA_TRC_FILE(FCS, RPORT_API);
+
+/**
+ * rport_api.c Remote port implementation.
+ */
+
+/**
+ * fcs_rport_api FCS rport API.
+ */
+
+/**
+ * Direct API to add a target by port wwn. This interface is used, for
+ * example, by bios when target pwwn is known from boot lun configuration.
+ */
+bfa_status_t
+bfa_fcs_rport_add(struct bfa_fcs_port_s *port, wwn_t *pwwn,
+ struct bfa_fcs_rport_s *rport,
+ struct bfad_rport_s *rport_drv)
+{
+ bfa_trc(port->fcs, *pwwn);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Direct API to remove a target and its associated resources. This
+ * interface is used, for example, by vmware driver to remove target
+ * ports from the target list for a VM.
+ */
+bfa_status_t
+bfa_fcs_rport_remove(struct bfa_fcs_rport_s *rport_in)
+{
+
+ struct bfa_fcs_rport_s *rport;
+
+ bfa_trc(rport_in->fcs, rport_in->pwwn);
+
+ rport = bfa_fcs_port_get_rport_by_pwwn(rport_in->port, rport_in->pwwn);
+ if (rport == NULL) {
+ /*
+ * TBD Error handling
+ */
+ bfa_trc(rport_in->fcs, rport_in->pid);
+ return BFA_STATUS_UNKNOWN_RWWN;
+ }
+
+ /*
+ * TBD if this remote port is online, send a logo
+ */
+ return BFA_STATUS_OK;
+
+}
+
+/**
+ * Remote device status for display/debug.
+ */
+void
+bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport,
+ struct bfa_rport_attr_s *rport_attr)
+{
+ struct bfa_rport_qos_attr_s qos_attr;
+ struct bfa_fcs_port_s *port = rport->port;
+
+ bfa_os_memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s));
+
+ rport_attr->pid = rport->pid;
+ rport_attr->pwwn = rport->pwwn;
+ rport_attr->nwwn = rport->nwwn;
+ rport_attr->cos_supported = rport->fc_cos;
+ rport_attr->df_sz = rport->maxfrsize;
+ rport_attr->state = bfa_fcs_rport_get_state(rport);
+ rport_attr->fc_cos = rport->fc_cos;
+ rport_attr->cisc = rport->cisc;
+ rport_attr->scsi_function = rport->scsi_function;
+ rport_attr->curr_speed = rport->rpf.rpsc_speed;
+ rport_attr->assigned_speed = rport->rpf.assigned_speed;
+
+ bfa_rport_get_qos_attr(rport->bfa_rport, &qos_attr);
+ rport_attr->qos_attr = qos_attr;
+
+ rport_attr->trl_enforced = BFA_FALSE;
+ if (bfa_pport_is_ratelim(port->fcs->bfa)) {
+ if ((rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN) ||
+ (rport->rpf.rpsc_speed <
+ bfa_fcs_port_get_rport_max_speed(port)))
+ rport_attr->trl_enforced = BFA_TRUE;
+ }
+
+ /*
+ * TODO
+ * rport->symname
+ */
+}
+
+/**
+ * Per remote device statistics.
+ */
+void
+bfa_fcs_rport_get_stats(struct bfa_fcs_rport_s *rport,
+ struct bfa_rport_stats_s *stats)
+{
+ *stats = rport->stats;
+}
+
+void
+bfa_fcs_rport_clear_stats(struct bfa_fcs_rport_s *rport)
+{
+ bfa_os_memset((char *)&rport->stats, 0,
+ sizeof(struct bfa_rport_stats_s));
+}
+
+struct bfa_fcs_rport_s *
+bfa_fcs_rport_lookup(struct bfa_fcs_port_s *port, wwn_t rpwwn)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ rport = bfa_fcs_port_get_rport_by_pwwn(port, rpwwn);
+ if (rport == NULL) {
+ /*
+ * TBD Error handling
+ */
+ }
+
+ return rport;
+}
+
+struct bfa_fcs_rport_s *
+bfa_fcs_rport_lookup_by_nwwn(struct bfa_fcs_port_s *port, wwn_t rnwwn)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ rport = bfa_fcs_port_get_rport_by_nwwn(port, rnwwn);
+ if (rport == NULL) {
+ /*
+ * TBD Error handling
+ */
+ }
+
+ return rport;
+}
+
+/*
+ * This API is to set the Rport's speed. Should be used when RPSC is not
+ * supported by the rport.
+ */
+void
+bfa_fcs_rport_set_speed(struct bfa_fcs_rport_s *rport,
+ enum bfa_pport_speed speed)
+{
+ rport->rpf.assigned_speed = speed;
+
+ /* Set this speed in f/w only if the RPSC speed is not available */
+ if (rport->rpf.rpsc_speed == BFA_PPORT_SPEED_UNKNOWN)
+ bfa_rport_speed(rport->bfa_rport, speed);
+}
+
+
diff --git a/drivers/scsi/bfa/rport_ftrs.c b/drivers/scsi/bfa/rport_ftrs.c
new file mode 100644
index 000000000000..e1932c885ac2
--- /dev/null
+++ b/drivers/scsi/bfa/rport_ftrs.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * rport_ftrs.c Remote port features (RPF) implementation.
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcbuild.h"
+#include "fcs_rport.h"
+#include "fcs_lport.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs.h"
+
+BFA_TRC_FILE(FCS, RPORT_FTRS);
+
+#define BFA_FCS_RPF_RETRIES (3)
+#define BFA_FCS_RPF_RETRY_TIMEOUT (1000) /* 1 sec (In millisecs) */
+
+static void bfa_fcs_rpf_send_rpsc2(void *rport_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_rpf_rpsc2_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 void bfa_fcs_rpf_timeout(void *arg);
+
+/**
+ * fcs_rport_ftrs_sm FCS rport state machine events
+ */
+
+enum rpf_event {
+ RPFSM_EVENT_RPORT_OFFLINE = 1, /* Rport offline */
+ RPFSM_EVENT_RPORT_ONLINE = 2, /* Rport online */
+ RPFSM_EVENT_FCXP_SENT = 3, /* Frame from has been sent */
+ RPFSM_EVENT_TIMEOUT = 4, /* Rport SM timeout event */
+ RPFSM_EVENT_RPSC_COMP = 5,
+ RPFSM_EVENT_RPSC_FAIL = 6,
+ RPFSM_EVENT_RPSC_ERROR = 7,
+};
+
+static void bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+static void bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+static void bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+static void bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+static void bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+static void bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf,
+ enum rpf_event event);
+
+static void
+bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ 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;
+ bfa_fcs_rpf_send_rpsc2(rpf, NULL);
+ break;
+ };
+
+ case RPFSM_EVENT_RPORT_OFFLINE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPFSM_EVENT_FCXP_SENT:
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc);
+ break;
+
+ 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;
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (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)
+ bfa_rport_speed(rport->bfa_rport, rpf->rpsc_speed);
+ else if (rpf->assigned_speed != BFA_PPORT_SPEED_UNKNOWN)
+ bfa_rport_speed(rport->bfa_rport, rpf->assigned_speed);
+ break;
+
+ case RPFSM_EVENT_RPSC_FAIL:
+ /* RPSC not supported by rport */
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online);
+ break;
+
+ case RPFSM_EVENT_RPSC_ERROR:
+ /* need to retry...delayed a bit. */
+ if (rpf->rpsc_retries++ < BFA_FCS_RPF_RETRIES) {
+ bfa_timer_start(rport->fcs->bfa, &rpf->timer,
+ bfa_fcs_rpf_timeout, rpf,
+ BFA_FCS_RPF_RETRY_TIMEOUT);
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_retry);
+ } else {
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online);
+ }
+ break;
+
+ case RPFSM_EVENT_RPORT_OFFLINE:
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
+ bfa_fcxp_discard(rpf->fcxp);
+ rpf->rpsc_retries = 0;
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ 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:
+ bfa_timer_stop(&rpf->timer);
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
+ rpf->rpsc_retries = 0;
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ case RPFSM_EVENT_RPORT_OFFLINE:
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline);
+ rpf->rpsc_retries = 0;
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event)
+{
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_trc(rport->fcs, event);
+
+ switch (event) {
+ 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:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+/**
+ * Called when Rport is created.
+ */
+void bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport)
+{
+ struct bfa_fcs_rpf_s *rpf = &rport->rpf;
+
+ bfa_trc(rport->fcs, rport->pid);
+ rpf->rport = rport;
+
+ bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_uninit);
+}
+
+/**
+ * Called when Rport becomes online
+ */
+void bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport)
+{
+ bfa_trc(rport->fcs, rport->pid);
+
+ if (__fcs_min_cfg(rport->port->fcs))
+ return;
+
+ if (bfa_fcs_fabric_is_switched(rport->port->fabric))
+ bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_ONLINE);
+}
+
+/**
+ * Called when Rport becomes offline
+ */
+void bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport)
+{
+ bfa_trc(rport->fcs, rport->pid);
+
+ if (__fcs_min_cfg(rport->port->fcs))
+ return;
+
+ bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_OFFLINE);
+}
+
+static void
+bfa_fcs_rpf_timeout(void *arg)
+{
+ struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) arg;
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+
+ bfa_trc(rport->fcs, rport->pid);
+ bfa_sm_send_event(rpf, RPFSM_EVENT_TIMEOUT);
+}
+
+static void
+bfa_fcs_rpf_send_rpsc2(void *rpf_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *)rpf_cbarg;
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+ struct bfa_fcs_port_s *port = rport->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(rport->fcs, rport->pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &rpf->fcxp_wqe,
+ bfa_fcs_rpf_send_rpsc2, rpf);
+ return;
+ }
+ rpf->fcxp = fcxp;
+
+ len = fc_rpsc2_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid,
+ bfa_fcs_port_get_fcid(port), &rport->pid, 1);
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_rpf_rpsc2_response,
+ rpf, FC_MAX_PDUSZ, FC_RA_TOV);
+ rport->stats.rpsc_sent++;
+ bfa_sm_send_event(rpf, RPFSM_EVENT_FCXP_SENT);
+
+}
+
+static void
+bfa_fcs_rpf_rpsc2_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_rpf_s *rpf = (struct bfa_fcs_rpf_s *) cbarg;
+ struct bfa_fcs_rport_s *rport = rpf->rport;
+ struct fc_ls_rjt_s *ls_rjt;
+ struct fc_rpsc2_acc_s *rpsc2_acc;
+ u16 num_ents;
+
+ bfa_trc(rport->fcs, req_status);
+
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(rport->fcs, req_status);
+ if (req_status == BFA_STATUS_ETIMER)
+ rport->stats.rpsc_failed++;
+ bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
+ return;
+ }
+
+ rpsc2_acc = (struct fc_rpsc2_acc_s *) BFA_FCXP_RSP_PLD(fcxp);
+ if (rpsc2_acc->els_cmd == FC_ELS_ACC) {
+ rport->stats.rpsc_accs++;
+ num_ents = bfa_os_ntohs(rpsc2_acc->num_pids);
+ bfa_trc(rport->fcs, num_ents);
+ if (num_ents > 0) {
+ bfa_assert(rpsc2_acc->port_info[0].pid != rport->pid);
+ bfa_trc(rport->fcs,
+ bfa_os_ntohs(rpsc2_acc->port_info[0].pid));
+ bfa_trc(rport->fcs,
+ bfa_os_ntohs(rpsc2_acc->port_info[0].speed));
+ bfa_trc(rport->fcs,
+ bfa_os_ntohs(rpsc2_acc->port_info[0].index));
+ bfa_trc(rport->fcs,
+ rpsc2_acc->port_info[0].type);
+
+ if (rpsc2_acc->port_info[0].speed == 0) {
+ bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
+ return;
+ }
+
+ rpf->rpsc_speed = fc_rpsc_operspeed_to_bfa_speed(
+ bfa_os_ntohs(rpsc2_acc->port_info[0].speed));
+
+ bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_COMP);
+ }
+ } else {
+ ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
+ 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)
+ bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_FAIL);
+ else
+ bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR);
+ }
+}
diff --git a/drivers/scsi/bfa/scn.c b/drivers/scsi/bfa/scn.c
new file mode 100644
index 000000000000..bd4771ff62c8
--- /dev/null
+++ b/drivers/scsi/bfa/scn.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include "fcs_lport.h"
+#include "fcs_rport.h"
+#include "fcs_ms.h"
+#include "fcs_trcmod.h"
+#include "fcs_fcxp.h"
+#include "fcs.h"
+#include "lport_priv.h"
+
+BFA_TRC_FILE(FCS, SCN);
+
+#define FC_QOS_RSCN_EVENT 0x0c
+#define FC_FABRIC_NAME_RSCN_EVENT 0x0d
+
+/*
+ * forward declarations
+ */
+static void bfa_fcs_port_scn_send_scr(void *scn_cbarg,
+ struct bfa_fcxp_s *fcxp_alloced);
+static void bfa_fcs_port_scn_scr_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 void bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs);
+static void bfa_fcs_port_scn_timeout(void *arg);
+
+/**
+ * fcs_scm_sm FCS SCN state machine
+ */
+
+/**
+ * VPort SCN State Machine events
+ */
+enum port_scn_event {
+ SCNSM_EVENT_PORT_ONLINE = 1,
+ SCNSM_EVENT_PORT_OFFLINE = 2,
+ SCNSM_EVENT_RSP_OK = 3,
+ SCNSM_EVENT_RSP_ERROR = 4,
+ SCNSM_EVENT_TIMEOUT = 5,
+ SCNSM_EVENT_SCR_SENT = 6,
+};
+
+static void bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event);
+static void bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event);
+static void bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event);
+static void bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event);
+static void bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event);
+
+/**
+ * Starting state - awaiting link up.
+ */
+static void
+bfa_fcs_port_scn_sm_offline(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event)
+{
+ switch (event) {
+ case SCNSM_EVENT_PORT_ONLINE:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr);
+ bfa_fcs_port_scn_send_scr(scn, NULL);
+ break;
+
+ case SCNSM_EVENT_PORT_OFFLINE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_scn_sm_sending_scr(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event)
+{
+ switch (event) {
+ case SCNSM_EVENT_SCR_SENT:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr);
+ break;
+
+ case SCNSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
+ bfa_fcxp_walloc_cancel(scn->port->fcs->bfa, &scn->fcxp_wqe);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_scn_sm_scr(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event)
+{
+ struct bfa_fcs_port_s *port = scn->port;
+
+ switch (event) {
+ case SCNSM_EVENT_RSP_OK:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_online);
+ break;
+
+ case SCNSM_EVENT_RSP_ERROR:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_scr_retry);
+ bfa_timer_start(port->fcs->bfa, &scn->timer,
+ bfa_fcs_port_scn_timeout, scn,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case SCNSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
+ bfa_fcxp_discard(scn->fcxp);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_scn_sm_scr_retry(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event)
+{
+ switch (event) {
+ case SCNSM_EVENT_TIMEOUT:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_sending_scr);
+ bfa_fcs_port_scn_send_scr(scn, NULL);
+ break;
+
+ case SCNSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
+ bfa_timer_stop(&scn->timer);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+static void
+bfa_fcs_port_scn_sm_online(struct bfa_fcs_port_scn_s *scn,
+ enum port_scn_event event)
+{
+ switch (event) {
+ case SCNSM_EVENT_PORT_OFFLINE:
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * fcs_scn_private FCS SCN private functions
+ */
+
+/**
+ * This routine will be called to send a SCR command.
+ */
+static void
+bfa_fcs_port_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced)
+{
+ struct bfa_fcs_port_scn_s *scn = scn_cbarg;
+ struct bfa_fcs_port_s *port = scn->port;
+ struct fchs_s fchs;
+ int len;
+ struct bfa_fcxp_s *fcxp;
+
+ bfa_trc(port->fcs, port->pid);
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp) {
+ bfa_fcxp_alloc_wait(port->fcs->bfa, &scn->fcxp_wqe,
+ bfa_fcs_port_scn_send_scr, scn);
+ return;
+ }
+ scn->fcxp = fcxp;
+
+ /*
+ * Handle VU registrations for Base port only
+ */
+ if ((!port->vport) && bfa_ioc_get_fcmode(&port->fcs->bfa->ioc)) {
+ len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp),
+ bfa_lps_is_brcd_fabric(port->fabric->lps),
+ port->pid, 0);
+ } else {
+ len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), BFA_FALSE,
+ port->pid, 0);
+ }
+
+ bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE,
+ FC_CLASS_3, len, &fchs, bfa_fcs_port_scn_scr_response,
+ (void *)scn, FC_MAX_PDUSZ, FC_RA_TOV);
+
+ bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT);
+}
+
+static void
+bfa_fcs_port_scn_scr_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_scn_s *scn = (struct bfa_fcs_port_scn_s *)cbarg;
+ struct bfa_fcs_port_s *port = scn->port;
+ struct fc_els_cmd_s *els_cmd;
+ struct fc_ls_rjt_s *ls_rjt;
+
+ bfa_trc(port->fcs, port->port_cfg.pwwn);
+
+ /*
+ * Sanity Checks
+ */
+ if (req_status != BFA_STATUS_OK) {
+ bfa_trc(port->fcs, req_status);
+ bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
+ return;
+ }
+
+ els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ switch (els_cmd->els_code) {
+
+ case FC_ELS_ACC:
+ bfa_sm_send_event(scn, SCNSM_EVENT_RSP_OK);
+ break;
+
+ case FC_ELS_LS_RJT:
+
+ ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp);
+
+ bfa_trc(port->fcs, ls_rjt->reason_code);
+ bfa_trc(port->fcs, ls_rjt->reason_code_expl);
+
+ bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
+ break;
+
+ default:
+ bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR);
+ }
+}
+
+/*
+ * Send a LS Accept
+ */
+static void
+bfa_fcs_port_scn_send_ls_acc(struct bfa_fcs_port_s *port,
+ struct fchs_s *rx_fchs)
+{
+ struct fchs_s fchs;
+ struct bfa_fcxp_s *fcxp;
+ struct bfa_rport_s *bfa_rport = NULL;
+ int len;
+
+ bfa_trc(port->fcs, rx_fchs->s_id);
+
+ fcxp = bfa_fcs_fcxp_alloc(port->fcs);
+ if (!fcxp)
+ return;
+
+ len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rx_fchs->s_id,
+ bfa_fcs_port_get_fcid(port), rx_fchs->ox_id);
+
+ bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag,
+ BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL,
+ FC_MAX_PDUSZ, 0);
+}
+
+/**
+ * This routine will be called by bfa_timer on timer timeouts.
+ *
+ * param[in] vport - pointer to bfa_fcs_port_t.
+ * param[out] vport_status - pointer to return vport status in
+ *
+ * return
+ * void
+ *
+* Special Considerations:
+ *
+ * note
+ */
+static void
+bfa_fcs_port_scn_timeout(void *arg)
+{
+ struct bfa_fcs_port_scn_s *scn = (struct bfa_fcs_port_scn_s *)arg;
+
+ bfa_sm_send_event(scn, SCNSM_EVENT_TIMEOUT);
+}
+
+
+
+/**
+ * fcs_scn_public FCS state change notification public interfaces
+ */
+
+/*
+ * Functions called by port/fab
+ */
+void
+bfa_fcs_port_scn_init(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);
+
+ scn->port = port;
+ bfa_sm_set_state(scn, bfa_fcs_port_scn_sm_offline);
+}
+
+void
+bfa_fcs_port_scn_offline(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);
+
+ scn->port = port;
+ bfa_sm_send_event(scn, SCNSM_EVENT_PORT_OFFLINE);
+}
+
+void
+bfa_fcs_port_scn_online(struct bfa_fcs_port_s *port)
+{
+ struct bfa_fcs_port_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port);
+
+ scn->port = port;
+ bfa_sm_send_event(scn, SCNSM_EVENT_PORT_ONLINE);
+}
+
+static void
+bfa_fcs_port_scn_portid_rscn(struct bfa_fcs_port_s *port, u32 rpid)
+{
+ struct bfa_fcs_rport_s *rport;
+
+ bfa_trc(port->fcs, rpid);
+
+ /**
+ * If this is an unknown device, then it just came online.
+ * Otherwise let rport handle the RSCN event.
+ */
+ rport = bfa_fcs_port_get_rport_by_pid(port, rpid);
+ if (rport == NULL) {
+ /*
+ * If min cfg mode is enabled, we donot need to
+ * discover any new rports.
+ */
+ if (!__fcs_min_cfg(port->fcs))
+ rport = bfa_fcs_rport_create(port, rpid);
+ } else {
+ bfa_fcs_rport_scn(rport);
+ }
+}
+
+/**
+ * rscn format based PID comparison
+ */
+#define __fc_pid_match(__c0, __c1, __fmt) \
+ (((__fmt) == FC_RSCN_FORMAT_FABRIC) || \
+ (((__fmt) == FC_RSCN_FORMAT_DOMAIN) && \
+ ((__c0)[0] == (__c1)[0])) || \
+ (((__fmt) == FC_RSCN_FORMAT_AREA) && \
+ ((__c0)[0] == (__c1)[0]) && \
+ ((__c0)[1] == (__c1)[1])))
+
+static void
+bfa_fcs_port_scn_multiport_rscn(struct bfa_fcs_port_s *port,
+ enum fc_rscn_format format, u32 rscn_pid)
+{
+ struct bfa_fcs_rport_s *rport;
+ struct list_head *qe, *qe_next;
+ u8 *c0, *c1;
+
+ bfa_trc(port->fcs, format);
+ bfa_trc(port->fcs, rscn_pid);
+
+ c0 = (u8 *) &rscn_pid;
+
+ list_for_each_safe(qe, qe_next, &port->rport_q) {
+ rport = (struct bfa_fcs_rport_s *)qe;
+ c1 = (u8 *) &rport->pid;
+ if (__fc_pid_match(c0, c1, format))
+ bfa_fcs_rport_scn(rport);
+ }
+}
+
+void
+bfa_fcs_port_scn_process_rscn(struct bfa_fcs_port_s *port, struct fchs_s *fchs,
+ u32 len)
+{
+ struct fc_rscn_pl_s *rscn = (struct fc_rscn_pl_s *) (fchs + 1);
+ int num_entries;
+ u32 rscn_pid;
+ bfa_boolean_t nsquery = BFA_FALSE;
+ int i = 0;
+
+ num_entries =
+ (bfa_os_ntohs(rscn->payldlen) -
+ sizeof(u32)) / sizeof(rscn->event[0]);
+
+ bfa_trc(port->fcs, num_entries);
+
+ port->stats.num_rscn++;
+
+ bfa_fcs_port_scn_send_ls_acc(port, fchs);
+
+ for (i = 0; i < num_entries; i++) {
+ rscn_pid = rscn->event[i].portid;
+
+ bfa_trc(port->fcs, rscn->event[i].format);
+ bfa_trc(port->fcs, rscn_pid);
+
+ switch (rscn->event[i].format) {
+ case FC_RSCN_FORMAT_PORTID:
+ if (rscn->event[i].qualifier == FC_QOS_RSCN_EVENT) {
+ /*
+ * Ignore this event. f/w would have processed
+ * it
+ */
+ bfa_trc(port->fcs, rscn_pid);
+ } else {
+ port->stats.num_portid_rscn++;
+ bfa_fcs_port_scn_portid_rscn(port, rscn_pid);
+ }
+ break;
+
+ case FC_RSCN_FORMAT_FABRIC:
+ if (rscn->event[i].qualifier ==
+ FC_FABRIC_NAME_RSCN_EVENT) {
+ bfa_fcs_port_ms_fabric_rscn(port);
+ break;
+ }
+ /*
+ * !!!!!!!!! Fall Through !!!!!!!!!!!!!
+ */
+
+ case FC_RSCN_FORMAT_AREA:
+ case FC_RSCN_FORMAT_DOMAIN:
+ nsquery = BFA_TRUE;
+ bfa_fcs_port_scn_multiport_rscn(port,
+ rscn->event[i].format,
+ rscn_pid);
+ break;
+
+ default:
+ bfa_assert(0);
+ nsquery = BFA_TRUE;
+ }
+ }
+
+ /**
+ * If any of area, domain or fabric RSCN is received, do a fresh discovery
+ * to find new devices.
+ */
+ if (nsquery)
+ bfa_fcs_port_ns_query(port);
+}
+
+
diff --git a/drivers/scsi/bfa/vfapi.c b/drivers/scsi/bfa/vfapi.c
new file mode 100644
index 000000000000..391a4790bebd
--- /dev/null
+++ b/drivers/scsi/bfa/vfapi.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * vfapi.c Fabric module implementation.
+ */
+
+#include "fcs_fabric.h"
+#include "fcs_trcmod.h"
+
+BFA_TRC_FILE(FCS, VFAPI);
+
+/**
+ * fcs_vf_api virtual fabrics API
+ */
+
+/**
+ * Enable VF mode.
+ *
+ * @param[in] fcs fcs module instance
+ * @param[in] vf_id default vf_id of port, FC_VF_ID_NULL
+ * to use standard default vf_id of 1.
+ *
+ * @retval BFA_STATUS_OK vf mode is enabled
+ * @retval BFA_STATUS_BUSY Port is active. Port must be disabled
+ * before VF mode can be enabled.
+ */
+bfa_status_t
+bfa_fcs_vf_mode_enable(struct bfa_fcs_s *fcs, u16 vf_id)
+{
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Disable VF mode.
+ *
+ * @param[in] fcs fcs module instance
+ *
+ * @retval BFA_STATUS_OK vf mode is disabled
+ * @retval BFA_STATUS_BUSY VFs are present and being used. All
+ * VFs must be deleted before disabling
+ * VF mode.
+ */
+bfa_status_t
+bfa_fcs_vf_mode_disable(struct bfa_fcs_s *fcs)
+{
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Create a new VF instance.
+ *
+ * A new VF is created using the given VF configuration. A VF is identified
+ * by VF id. No duplicate VF creation is allowed with the same VF id. Once
+ * a VF is created, VF is automatically started after link initialization
+ * and EVFP exchange is completed.
+ *
+ * param[in] vf - FCS vf data structure. Memory is
+ * allocated by caller (driver)
+ * param[in] fcs - FCS module
+ * param[in] vf_cfg - VF configuration
+ * param[in] vf_drv - Opaque handle back to the driver's
+ * virtual vf structure
+ *
+ * retval BFA_STATUS_OK VF creation is successful
+ * retval BFA_STATUS_FAILED VF creation failed
+ * retval BFA_STATUS_EEXIST A VF exists with the given vf_id
+ */
+bfa_status_t
+bfa_fcs_vf_create(bfa_fcs_vf_t *vf, struct bfa_fcs_s *fcs, u16 vf_id,
+ struct bfa_port_cfg_s *port_cfg, struct bfad_vf_s *vf_drv)
+{
+ bfa_trc(fcs, vf_id);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Use this function to delete a BFA VF object. VF object should
+ * be stopped before this function call.
+ *
+ * param[in] vf - pointer to bfa_vf_t.
+ *
+ * retval BFA_STATUS_OK On vf deletion success
+ * retval BFA_STATUS_BUSY VF is not in a stopped state
+ * retval BFA_STATUS_INPROGRESS VF deletion in in progress
+ */
+bfa_status_t
+bfa_fcs_vf_delete(bfa_fcs_vf_t *vf)
+{
+ bfa_trc(vf->fcs, vf->vf_id);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Start participation in VF. This triggers login to the virtual fabric.
+ *
+ * param[in] vf - pointer to bfa_vf_t.
+ *
+ * return None
+ */
+void
+bfa_fcs_vf_start(bfa_fcs_vf_t *vf)
+{
+ bfa_trc(vf->fcs, vf->vf_id);
+}
+
+/**
+ * Logout with the virtual fabric.
+ *
+ * param[in] vf - pointer to bfa_vf_t.
+ *
+ * retval BFA_STATUS_OK On success.
+ * retval BFA_STATUS_INPROGRESS VF is being stopped.
+ */
+bfa_status_t
+bfa_fcs_vf_stop(bfa_fcs_vf_t *vf)
+{
+ bfa_trc(vf->fcs, vf->vf_id);
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Returns attributes of the given VF.
+ *
+ * param[in] vf pointer to bfa_vf_t.
+ * param[out] vf_attr vf attributes returned
+ *
+ * return None
+ */
+void
+bfa_fcs_vf_get_attr(bfa_fcs_vf_t *vf, struct bfa_vf_attr_s *vf_attr)
+{
+ bfa_trc(vf->fcs, vf->vf_id);
+}
+
+/**
+ * Return statistics associated with the given vf.
+ *
+ * param[in] vf pointer to bfa_vf_t.
+ * param[out] vf_stats vf statistics returned
+ *
+ * @return None
+ */
+void
+bfa_fcs_vf_get_stats(bfa_fcs_vf_t *vf, struct bfa_vf_stats_s *vf_stats)
+{
+ bfa_os_memcpy(vf_stats, &vf->stats, sizeof(struct bfa_vf_stats_s));
+ return;
+}
+
+void
+/**
+ * clear statistics associated with the given vf.
+ *
+ * param[in] vf pointer to bfa_vf_t.
+ *
+ * @return None
+ */
+bfa_fcs_vf_clear_stats(bfa_fcs_vf_t *vf)
+{
+ bfa_os_memset(&vf->stats, 0, sizeof(struct bfa_vf_stats_s));
+ return;
+}
+
+/**
+ * Returns FCS vf structure for a given vf_id.
+ *
+ * param[in] vf_id - VF_ID
+ *
+ * return
+ * If lookup succeeds, retuns fcs vf object, otherwise returns NULL
+ */
+bfa_fcs_vf_t *
+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;
+
+ /**
+ * @todo vf support
+ */
+
+ return NULL;
+}
+
+/**
+ * Returns driver VF structure for a given FCS vf.
+ *
+ * param[in] vf - pointer to bfa_vf_t
+ *
+ * return Driver VF structure
+ */
+struct bfad_vf_s *
+bfa_fcs_vf_get_drv_vf(bfa_fcs_vf_t *vf)
+{
+ bfa_assert(vf);
+ bfa_trc(vf->fcs, vf->vf_id);
+ return vf->vf_drv;
+}
+
+/**
+ * Return the list of VFs configured.
+ *
+ * param[in] fcs fcs module instance
+ * param[out] vf_ids returned list of vf_ids
+ * param[in,out] nvfs in:size of vf_ids array,
+ * out:total elements present,
+ * actual elements returned is limited by the size
+ *
+ * return Driver VF structure
+ */
+void
+bfa_fcs_vf_list(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs)
+{
+ bfa_trc(fcs, *nvfs);
+}
+
+/**
+ * Return the list of all VFs visible from fabric.
+ *
+ * param[in] fcs fcs module instance
+ * param[out] vf_ids returned list of vf_ids
+ * param[in,out] nvfs in:size of vf_ids array,
+ * out:total elements present,
+ * actual elements returned is limited by the size
+ *
+ * return Driver VF structure
+ */
+void
+bfa_fcs_vf_list_all(struct bfa_fcs_s *fcs, u16 *vf_ids, int *nvfs)
+{
+ bfa_trc(fcs, *nvfs);
+}
+
+/**
+ * Return the list of local logical ports present in the given VF.
+ *
+ * param[in] vf vf for which logical ports are returned
+ * param[out] lpwwn returned logical port wwn list
+ * param[in,out] nlports in:size of lpwwn list;
+ * out:total elements present,
+ * actual elements returned is limited by the size
+ *
+ */
+void
+bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports)
+{
+ struct list_head *qe;
+ struct bfa_fcs_vport_s *vport;
+ int i;
+ struct bfa_fcs_s *fcs;
+
+ if (vf == NULL || lpwwn == NULL || *nlports == 0)
+ return;
+
+ fcs = vf->fcs;
+
+ bfa_trc(fcs, vf->vf_id);
+ bfa_trc(fcs, (u32) *nlports);
+
+ i = 0;
+ lpwwn[i++] = vf->bport.port_cfg.pwwn;
+
+ list_for_each(qe, &vf->vport_q) {
+ if (i >= *nlports)
+ break;
+
+ vport = (struct bfa_fcs_vport_s *) qe;
+ lpwwn[i++] = vport->lport.port_cfg.pwwn;
+ }
+
+ bfa_trc(fcs, i);
+ *nlports = i;
+ return;
+}
+
+
diff --git a/drivers/scsi/bfa/vport.c b/drivers/scsi/bfa/vport.c
new file mode 100644
index 000000000000..e90f1e38c32d
--- /dev/null
+++ b/drivers/scsi/bfa/vport.c
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux driver for Brocade Fibre Channel Host Bus Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+/**
+ * bfa_fcs_vport.c FCS virtual port state machine
+ */
+
+#include <bfa.h>
+#include <bfa_svc.h>
+#include <fcbuild.h>
+#include "fcs_fabric.h"
+#include "fcs_lport.h"
+#include "fcs_vport.h"
+#include "fcs_trcmod.h"
+#include "fcs.h"
+#include <aen/bfa_aen_lport.h>
+
+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 BFA_FCS_VPORT_MAX_RETRIES 5
+/*
+ * Forward declarations
+ */
+static void bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport);
+static void bfa_fcs_vport_timeout(void *vport_arg);
+static void bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport);
+static void bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport);
+
+/**
+ * fcs_vport_sm FCS virtual port state machine
+ */
+
+/**
+ * VPort State Machine events
+ */
+enum bfa_fcs_vport_event {
+ BFA_FCS_VPORT_SM_CREATE = 1, /* vport create event */
+ BFA_FCS_VPORT_SM_DELETE = 2, /* vport delete event */
+ BFA_FCS_VPORT_SM_START = 3, /* vport start request */
+ BFA_FCS_VPORT_SM_STOP = 4, /* stop: unsupported */
+ BFA_FCS_VPORT_SM_ONLINE = 5, /* fabric online */
+ BFA_FCS_VPORT_SM_OFFLINE = 6, /* fabric offline event */
+ BFA_FCS_VPORT_SM_FRMSENT = 7, /* fdisc/logo sent events */
+ BFA_FCS_VPORT_SM_RSP_OK = 8, /* good response */
+ BFA_FCS_VPORT_SM_RSP_ERROR = 9, /* error/bad response */
+ BFA_FCS_VPORT_SM_TIMEOUT = 10, /* delay timer event */
+ BFA_FCS_VPORT_SM_DELCOMP = 11, /* lport delete completion */
+ BFA_FCS_VPORT_SM_RSP_DUP_WWN = 12, /* Dup wnn error */
+ BFA_FCS_VPORT_SM_RSP_FAILED = 13, /* non-retryable failure */
+};
+
+static void bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event);
+static void bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event);
+static void bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event);
+static void bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event);
+static void bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event);
+static void bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event);
+static void bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event);
+static void bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event);
+static void bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event);
+static void bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event);
+
+static struct bfa_sm_table_s vport_sm_table[] = {
+ {BFA_SM(bfa_fcs_vport_sm_uninit), BFA_FCS_VPORT_UNINIT},
+ {BFA_SM(bfa_fcs_vport_sm_created), BFA_FCS_VPORT_CREATED},
+ {BFA_SM(bfa_fcs_vport_sm_offline), BFA_FCS_VPORT_OFFLINE},
+ {BFA_SM(bfa_fcs_vport_sm_fdisc), BFA_FCS_VPORT_FDISC},
+ {BFA_SM(bfa_fcs_vport_sm_fdisc_retry), BFA_FCS_VPORT_FDISC_RETRY},
+ {BFA_SM(bfa_fcs_vport_sm_online), BFA_FCS_VPORT_ONLINE},
+ {BFA_SM(bfa_fcs_vport_sm_deleting), BFA_FCS_VPORT_DELETING},
+ {BFA_SM(bfa_fcs_vport_sm_cleanup), BFA_FCS_VPORT_CLEANUP},
+ {BFA_SM(bfa_fcs_vport_sm_logo), BFA_FCS_VPORT_LOGO},
+ {BFA_SM(bfa_fcs_vport_sm_error), BFA_FCS_VPORT_ERROR}
+};
+
+/**
+ * Beginning state.
+ */
+static void
+bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event)
+{
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+ bfa_trc(__vport_fcs(vport), event);
+
+ switch (event) {
+ case BFA_FCS_VPORT_SM_CREATE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_created);
+ bfa_fcs_fabric_addvport(__vport_fabric(vport), vport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Created state - a start event is required to start up the state machine.
+ */
+static void
+bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event)
+{
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+ bfa_trc(__vport_fcs(vport), event);
+
+ switch (event) {
+ case BFA_FCS_VPORT_SM_START:
+ if (bfa_fcs_fabric_is_online(__vport_fabric(vport))
+ && bfa_fcs_fabric_npiv_capable(__vport_fabric(vport))) {
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc);
+ bfa_fcs_vport_do_fdisc(vport);
+ } else {
+ /**
+ * Fabric is offline or not NPIV capable, stay in
+ * offline state.
+ */
+ vport->vport_stats.fab_no_npiv++;
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
+ }
+ break;
+
+ case BFA_FCS_VPORT_SM_DELETE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
+ bfa_fcs_port_delete(&vport->lport);
+ break;
+
+ case BFA_FCS_VPORT_SM_ONLINE:
+ case BFA_FCS_VPORT_SM_OFFLINE:
+ /**
+ * Ignore ONLINE/OFFLINE events from fabric till vport is started.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Offline state - awaiting ONLINE event from fabric SM.
+ */
+static void
+bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event)
+{
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+ bfa_trc(__vport_fcs(vport), event);
+
+ switch (event) {
+ case BFA_FCS_VPORT_SM_DELETE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
+ bfa_fcs_port_delete(&vport->lport);
+ break;
+
+ case BFA_FCS_VPORT_SM_ONLINE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc);
+ vport->fdisc_retries = 0;
+ bfa_fcs_vport_do_fdisc(vport);
+ break;
+
+ case BFA_FCS_VPORT_SM_OFFLINE:
+ /*
+ * This can happen if the vport couldn't be initialzied due
+ * the fact that the npiv was not enabled on the switch. In
+ * that case we will put the vport in offline state. However,
+ * the link can go down and cause the this event to be sent when
+ * we are already offline. Ignore it.
+ */
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * FDISC is sent and awaiting reply from fabric.
+ */
+static void
+bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event)
+{
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+ bfa_trc(__vport_fcs(vport), event);
+
+ switch (event) {
+ case BFA_FCS_VPORT_SM_DELETE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo);
+ bfa_lps_discard(vport->lps);
+ bfa_fcs_vport_do_logo(vport);
+ break;
+
+ case BFA_FCS_VPORT_SM_OFFLINE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
+ bfa_lps_discard(vport->lps);
+ break;
+
+ case BFA_FCS_VPORT_SM_RSP_OK:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_online);
+ bfa_fcs_port_online(&vport->lport);
+ break;
+
+ case BFA_FCS_VPORT_SM_RSP_ERROR:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc_retry);
+ bfa_timer_start(__vport_bfa(vport), &vport->timer,
+ bfa_fcs_vport_timeout, vport,
+ BFA_FCS_RETRY_TIMEOUT);
+ break;
+
+ case BFA_FCS_VPORT_SM_RSP_FAILED:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
+ break;
+
+ case BFA_FCS_VPORT_SM_RSP_DUP_WWN:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_error);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * FDISC attempt failed - a timer is active to retry FDISC.
+ */
+static void
+bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event)
+{
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+ bfa_trc(__vport_fcs(vport), event);
+
+ switch (event) {
+ case BFA_FCS_VPORT_SM_DELETE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
+ bfa_timer_stop(&vport->timer);
+ bfa_fcs_port_delete(&vport->lport);
+ break;
+
+ case BFA_FCS_VPORT_SM_OFFLINE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
+ bfa_timer_stop(&vport->timer);
+ break;
+
+ case BFA_FCS_VPORT_SM_TIMEOUT:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc);
+ vport->vport_stats.fdisc_retries++;
+ vport->fdisc_retries++;
+ bfa_fcs_vport_do_fdisc(vport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Vport is online (FDISC is complete).
+ */
+static void
+bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event)
+{
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+ bfa_trc(__vport_fcs(vport), event);
+
+ switch (event) {
+ case BFA_FCS_VPORT_SM_DELETE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_deleting);
+ bfa_fcs_port_delete(&vport->lport);
+ break;
+
+ case BFA_FCS_VPORT_SM_OFFLINE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline);
+ bfa_lps_discard(vport->lps);
+ bfa_fcs_port_offline(&vport->lport);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Vport is being deleted - awaiting lport delete completion to send
+ * LOGO to fabric.
+ */
+static void
+bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event)
+{
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+ bfa_trc(__vport_fcs(vport), event);
+
+ switch (event) {
+ case BFA_FCS_VPORT_SM_DELETE:
+ break;
+
+ case BFA_FCS_VPORT_SM_DELCOMP:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo);
+ bfa_fcs_vport_do_logo(vport);
+ break;
+
+ case BFA_FCS_VPORT_SM_OFFLINE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup);
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * Error State.
+ * This state will be set when the Vport Creation fails due to errors like
+ * Dup WWN. In this state only operation allowed is a Vport Delete.
+ */
+static void
+bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event)
+{
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+ bfa_trc(__vport_fcs(vport), event);
+
+ switch (event) {
+ case BFA_FCS_VPORT_SM_DELETE:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
+ bfa_fcs_vport_free(vport);
+ break;
+
+ default:
+ bfa_trc(__vport_fcs(vport), event);
+ }
+}
+
+/**
+ * Lport cleanup is in progress since vport is being deleted. Fabric is
+ * offline, so no LOGO is needed to complete vport deletion.
+ */
+static void
+bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event)
+{
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+ bfa_trc(__vport_fcs(vport), event);
+
+ switch (event) {
+ case BFA_FCS_VPORT_SM_DELCOMP:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
+ bfa_fcs_vport_free(vport);
+ break;
+
+ case BFA_FCS_VPORT_SM_DELETE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+/**
+ * LOGO is sent to fabric. Vport delete is in progress. Lport delete cleanup
+ * is done.
+ */
+static void
+bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport,
+ enum bfa_fcs_vport_event event)
+{
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+ bfa_trc(__vport_fcs(vport), event);
+
+ switch (event) {
+ case BFA_FCS_VPORT_SM_OFFLINE:
+ bfa_lps_discard(vport->lps);
+ /*
+ * !!! fall through !!!
+ */
+
+ case BFA_FCS_VPORT_SM_RSP_OK:
+ case BFA_FCS_VPORT_SM_RSP_ERROR:
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
+ bfa_fcs_vport_free(vport);
+ break;
+
+ case BFA_FCS_VPORT_SM_DELETE:
+ break;
+
+ default:
+ bfa_assert(0);
+ }
+}
+
+
+
+/**
+ * fcs_vport_private FCS virtual port private functions
+ */
+
+/**
+ * Send AEN notification
+ */
+static void
+bfa_fcs_vport_aen_post(bfa_fcs_lport_t *port, enum bfa_lport_aen_event event)
+{
+ union bfa_aen_data_u aen_data;
+ struct bfa_log_mod_s *logmod = port->fcs->logm;
+ enum bfa_port_role role = port->port_cfg.roles;
+ wwn_t lpwwn = bfa_fcs_port_get_pwwn(port);
+ char lpwwn_ptr[BFA_STRING_32];
+ char *role_str[BFA_PORT_ROLE_FCP_MAX / 2 + 1] =
+ { "Initiator", "Target", "IPFC" };
+
+ wwn2str(lpwwn_ptr, lpwwn);
+
+ bfa_assert(role <= BFA_PORT_ROLE_FCP_MAX);
+
+ switch (event) {
+ case BFA_LPORT_AEN_NPIV_DUP_WWN:
+ bfa_log(logmod, BFA_AEN_LPORT_NPIV_DUP_WWN, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_NPIV_FABRIC_MAX:
+ bfa_log(logmod, BFA_AEN_LPORT_NPIV_FABRIC_MAX, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ case BFA_LPORT_AEN_NPIV_UNKNOWN:
+ bfa_log(logmod, BFA_AEN_LPORT_NPIV_UNKNOWN, lpwwn_ptr,
+ role_str[role / 2]);
+ break;
+ default:
+ break;
+ }
+
+ aen_data.lport.vf_id = port->fabric->vf_id;
+ aen_data.lport.roles = role;
+ aen_data.lport.ppwwn =
+ bfa_fcs_port_get_pwwn(bfa_fcs_get_base_port(port->fcs));
+ aen_data.lport.lpwwn = lpwwn;
+}
+
+/**
+ * This routine will be called to send a FDISC command.
+ */
+static void
+bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport)
+{
+ bfa_lps_fdisc(vport->lps, vport,
+ bfa_pport_get_maxfrsize(__vport_bfa(vport)),
+ __vport_pwwn(vport), __vport_nwwn(vport));
+ vport->vport_stats.fdisc_sent++;
+}
+
+static void
+bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport)
+{
+ u8 lsrjt_rsn = bfa_lps_get_lsrjt_rsn(vport->lps);
+ u8 lsrjt_expl = bfa_lps_get_lsrjt_expl(vport->lps);
+
+ bfa_trc(__vport_fcs(vport), lsrjt_rsn);
+ bfa_trc(__vport_fcs(vport), lsrjt_expl);
+
+ /*
+ * For certain reason codes, we don't want to retry.
+ */
+ switch (bfa_lps_get_lsrjt_expl(vport->lps)) {
+ case FC_LS_RJT_EXP_INV_PORT_NAME: /* by brocade */
+ case FC_LS_RJT_EXP_INVALID_NPORT_ID: /* by Cisco */
+ if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES)
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
+ else {
+ bfa_fcs_vport_aen_post(&vport->lport,
+ BFA_LPORT_AEN_NPIV_DUP_WWN);
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_DUP_WWN);
+ }
+ break;
+
+ case FC_LS_RJT_EXP_INSUFF_RES:
+ /*
+ * This means max logins per port/switch setting on the
+ * switch was exceeded.
+ */
+ if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES)
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
+ else {
+ bfa_fcs_vport_aen_post(&vport->lport,
+ BFA_LPORT_AEN_NPIV_FABRIC_MAX);
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_FAILED);
+ }
+ break;
+
+ default:
+ if (vport->fdisc_retries == 0) /* Print only once */
+ bfa_fcs_vport_aen_post(&vport->lport,
+ BFA_LPORT_AEN_NPIV_UNKNOWN);
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
+ }
+}
+
+/**
+ * Called to send a logout to the fabric. Used when a V-Port is
+ * deleted/stopped.
+ */
+static void
+bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport)
+{
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+
+ vport->vport_stats.logo_sent++;
+ bfa_lps_fdisclogo(vport->lps);
+}
+
+/**
+ * This routine will be called by bfa_timer on timer timeouts.
+ *
+ * param[in] vport - pointer to bfa_fcs_vport_t.
+ * param[out] vport_status - pointer to return vport status in
+ *
+ * return
+ * void
+ *
+* Special Considerations:
+ *
+ * note
+ */
+static void
+bfa_fcs_vport_timeout(void *vport_arg)
+{
+ struct bfa_fcs_vport_s *vport = (struct bfa_fcs_vport_s *)vport_arg;
+
+ vport->vport_stats.fdisc_timeouts++;
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_TIMEOUT);
+}
+
+static void
+bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport)
+{
+ bfa_fcs_fabric_delvport(__vport_fabric(vport), vport);
+ bfa_fcb_vport_delete(vport->vport_drv);
+ bfa_lps_delete(vport->lps);
+}
+
+
+
+/**
+ * fcs_vport_public FCS virtual port public interfaces
+ */
+
+/**
+ * Online notification from fabric SM.
+ */
+void
+bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport)
+{
+ vport->vport_stats.fab_online++;
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE);
+}
+
+/**
+ * Offline notification from fabric SM.
+ */
+void
+bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport)
+{
+ vport->vport_stats.fab_offline++;
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE);
+}
+
+/**
+ * Cleanup notification from fabric SM on link timer expiry.
+ */
+void
+bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport)
+{
+ vport->vport_stats.fab_cleanup++;
+}
+
+/**
+ * Delete completion callback from associated lport
+ */
+void
+bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport)
+{
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELCOMP);
+}
+
+/**
+ * Module initialization
+ */
+void
+bfa_fcs_vport_modinit(struct bfa_fcs_s *fcs)
+{
+}
+
+/**
+ * Module cleanup
+ */
+void
+bfa_fcs_vport_modexit(struct bfa_fcs_s *fcs)
+{
+ bfa_fcs_modexit_comp(fcs);
+}
+
+u32
+bfa_fcs_vport_get_max(struct bfa_fcs_s *fcs)
+{
+ struct bfa_ioc_attr_s ioc_attr;
+
+ 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;
+ else
+ return BFA_FCS_MAX_VPORTS_SUPP_CB;
+}
+
+
+
+/**
+ * fcs_vport_api Virtual port API
+ */
+
+/**
+ * Use this function to instantiate a new FCS vport object. This
+ * function will not trigger any HW initialization process (which will be
+ * done in vport_start() call)
+ *
+ * param[in] vport - pointer to bfa_fcs_vport_t. This space
+ * needs to be allocated by the driver.
+ * param[in] fcs - FCS instance
+ * param[in] vport_cfg - vport configuration
+ * param[in] vf_id - VF_ID if vport is created within a VF.
+ * FC_VF_ID_NULL to specify base fabric.
+ * param[in] vport_drv - Opaque handle back to the driver's vport
+ * structure
+ *
+ * retval BFA_STATUS_OK - on success.
+ * retval BFA_STATUS_FAILED - on failure.
+ */
+bfa_status_t
+bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs,
+ u16 vf_id, struct bfa_port_cfg_s *vport_cfg,
+ struct bfad_vport_s *vport_drv)
+{
+ if (vport_cfg->pwwn == 0)
+ return BFA_STATUS_INVALID_WWN;
+
+ if (bfa_fcs_port_get_pwwn(&fcs->fabric.bport) == vport_cfg->pwwn)
+ return BFA_STATUS_VPORT_WWN_BP;
+
+ if (bfa_fcs_vport_lookup(fcs, vf_id, vport_cfg->pwwn) != NULL)
+ return BFA_STATUS_VPORT_EXISTS;
+
+ if (bfa_fcs_fabric_vport_count(&fcs->fabric) ==
+ bfa_fcs_vport_get_max(fcs))
+ return BFA_STATUS_VPORT_MAX;
+
+ vport->lps = bfa_lps_alloc(fcs->bfa);
+ if (!vport->lps)
+ return BFA_STATUS_VPORT_MAX;
+
+ vport->vport_drv = vport_drv;
+ bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit);
+
+ bfa_fcs_lport_init(&vport->lport, fcs, vf_id, vport_cfg, vport);
+
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_CREATE);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Use this function initialize the vport.
+ *
+ * @param[in] vport - pointer to bfa_fcs_vport_t.
+ *
+ * @returns None
+ */
+bfa_status_t
+bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport)
+{
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_START);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Use this function quiese the vport object. This function will return
+ * immediately, when the vport is actually stopped, the
+ * bfa_drv_vport_stop_cb() will be called.
+ *
+ * param[in] vport - pointer to bfa_fcs_vport_t.
+ *
+ * return None
+ */
+bfa_status_t
+bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport)
+{
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOP);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Use this function to delete a vport object. Fabric object should
+ * be stopped before this function call.
+ *
+ * param[in] vport - pointer to bfa_fcs_vport_t.
+ *
+ * return None
+ */
+bfa_status_t
+bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport)
+{
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE);
+
+ return BFA_STATUS_OK;
+}
+
+/**
+ * Use this function to get vport's current status info.
+ *
+ * param[in] vport pointer to bfa_fcs_vport_t.
+ * param[out] attr pointer to return vport attributes
+ *
+ * return None
+ */
+void
+bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport,
+ struct bfa_vport_attr_s *attr)
+{
+ if (vport == NULL || attr == NULL)
+ return;
+
+ bfa_os_memset(attr, 0, sizeof(struct bfa_vport_attr_s));
+
+ bfa_fcs_port_get_attr(&vport->lport, &attr->port_attr);
+ attr->vport_state = bfa_sm_to_state(vport_sm_table, vport->sm);
+}
+
+/**
+ * Use this function to get vport's statistics.
+ *
+ * param[in] vport pointer to bfa_fcs_vport_t.
+ * param[out] stats pointer to return vport statistics in
+ *
+ * return None
+ */
+void
+bfa_fcs_vport_get_stats(struct bfa_fcs_vport_s *vport,
+ struct bfa_vport_stats_s *stats)
+{
+ *stats = vport->vport_stats;
+}
+
+/**
+ * Use this function to clear vport's statistics.
+ *
+ * param[in] vport pointer to bfa_fcs_vport_t.
+ *
+ * return None
+ */
+void
+bfa_fcs_vport_clr_stats(struct bfa_fcs_vport_s *vport)
+{
+ bfa_os_memset(&vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s));
+}
+
+/**
+ * Lookup a virtual port. Excludes base port from lookup.
+ */
+struct bfa_fcs_vport_s *
+bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t vpwwn)
+{
+ struct bfa_fcs_vport_s *vport;
+ struct bfa_fcs_fabric_s *fabric;
+
+ bfa_trc(fcs, vf_id);
+ bfa_trc(fcs, vpwwn);
+
+ fabric = bfa_fcs_vf_lookup(fcs, vf_id);
+ if (!fabric) {
+ bfa_trc(fcs, vf_id);
+ return NULL;
+ }
+
+ vport = bfa_fcs_fabric_vport_lookup(fabric, vpwwn);
+ return vport;
+}
+
+/**
+ * FDISC Response
+ */
+void
+bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status)
+{
+ struct bfa_fcs_vport_s *vport = uarg;
+
+ bfa_trc(__vport_fcs(vport), __vport_pwwn(vport));
+ bfa_trc(__vport_fcs(vport), status);
+
+ switch (status) {
+ case BFA_STATUS_OK:
+ /*
+ * Initialiaze the V-Port fields
+ */
+ __vport_fcid(vport) = bfa_lps_get_pid(vport->lps);
+ vport->vport_stats.fdisc_accepts++;
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK);
+ break;
+
+ case BFA_STATUS_INVALID_MAC:
+ /*
+ * Only for CNA
+ */
+ vport->vport_stats.fdisc_acc_bad++;
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
+
+ break;
+
+ case BFA_STATUS_EPROTOCOL:
+ switch (bfa_lps_get_extstatus(vport->lps)) {
+ case BFA_EPROTO_BAD_ACCEPT:
+ vport->vport_stats.fdisc_acc_bad++;
+ break;
+
+ case BFA_EPROTO_UNKNOWN_RSP:
+ vport->vport_stats.fdisc_unknown_rsp++;
+ break;
+
+ default:
+ break;
+ }
+
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
+ break;
+
+ case BFA_STATUS_FABRIC_RJT:
+ vport->vport_stats.fdisc_rejects++;
+ bfa_fcs_vport_fdisc_rejected(vport);
+ break;
+
+ default:
+ vport->vport_stats.fdisc_rsp_err++;
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR);
+ }
+}
+
+/**
+ * LOGO response
+ */
+void
+bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg)
+{
+ struct bfa_fcs_vport_s *vport = uarg;
+ bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK);
+}
+
+
diff --git a/drivers/scsi/bnx2i/bnx2i.h b/drivers/scsi/bnx2i/bnx2i.h
index d7576f28c6e9..5edde1a8c04d 100644
--- a/drivers/scsi/bnx2i/bnx2i.h
+++ b/drivers/scsi/bnx2i/bnx2i.h
@@ -100,6 +100,8 @@
#define CTX_OFFSET 0x10000
#define MAX_CID_CNT 0x4000
+#define BNX2I_570X_PAGE_SIZE_DEFAULT 4096
+
/* 5709 context registers */
#define BNX2_MQ_CONFIG2 0x00003d00
#define BNX2_MQ_CONFIG2_CONT_SZ (0x7L<<4)
diff --git a/drivers/scsi/bnx2i/bnx2i_hwi.c b/drivers/scsi/bnx2i/bnx2i_hwi.c
index 41e1b0e7e2ef..5c8d7630c13e 100644
--- a/drivers/scsi/bnx2i/bnx2i_hwi.c
+++ b/drivers/scsi/bnx2i/bnx2i_hwi.c
@@ -2386,7 +2386,7 @@ int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep)
ctx_sz = (config2 & BNX2_MQ_CONFIG2_CONT_SZ) >> 3;
if (ctx_sz)
reg_off = CTX_OFFSET + MAX_CID_CNT * MB_KERNEL_CTX_SIZE
- + PAGE_SIZE *
+ + BNX2I_570X_PAGE_SIZE_DEFAULT *
(((cid_num - first_l4l5) / ctx_sz) + 256);
else
reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num);
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 9a7ba71f1af4..cafb888c2376 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -1243,7 +1243,7 @@ bnx2i_session_create(struct iscsi_endpoint *ep,
cmds_max = BNX2I_SQ_WQES_MIN;
cls_session = iscsi_session_setup(&bnx2i_iscsi_transport, shost,
- cmds_max, sizeof(struct bnx2i_cmd),
+ cmds_max, 0, sizeof(struct bnx2i_cmd),
initial_cmdsn, ISCSI_MAX_TARGET);
if (!cls_session)
return NULL;
diff --git a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
index c399f485aa7d..2631bddd255e 100644
--- a/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
+++ b/drivers/scsi/cxgb3i/cxgb3i_iscsi.c
@@ -422,7 +422,7 @@ cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth,
BUG_ON(hba != iscsi_host_priv(shost));
cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost,
- cmds_max,
+ cmds_max, 0,
sizeof(struct iscsi_tcp_task) +
sizeof(struct cxgb3i_task_data),
initial_cmdsn, ISCSI_MAX_TARGET);
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 11c89311427e..268189d31d9c 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -500,8 +500,6 @@ static int mode_select_handle_sense(struct scsi_device *sdev,
if (!ret)
goto done;
- err = SCSI_DH_OK;
-
switch (sense_hdr.sense_key) {
case NO_SENSE:
case ABORTED_COMMAND:
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index c596ab5f05c3..a0e7e711ff9d 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -1,6 +1,6 @@
/*
* HighPoint RR3xxx/4xxx controller driver for Linux
- * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
+ * Copyright (C) 2006-2009 HighPoint Technologies, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,7 +41,7 @@ MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver");
static char driver_name[] = "hptiop";
static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver";
-static const char driver_ver[] = "v1.3 (071203)";
+static const char driver_ver[] = "v1.6 (090910)";
static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec);
static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag,
@@ -115,9 +115,13 @@ static void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba)
static int iop_intr_itl(struct hptiop_hba *hba)
{
struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop;
+ void __iomem *plx = hba->u.itl.plx;
u32 status;
int ret = 0;
+ if (plx && readl(plx + 0x11C5C) & 0xf)
+ writel(1, plx + 0x11C60);
+
status = readl(&iop->outbound_intstatus);
if (status & IOPMU_OUTBOUND_INT_MSG0) {
@@ -460,15 +464,25 @@ static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index)
static int hptiop_map_pci_bar_itl(struct hptiop_hba *hba)
{
+ struct pci_dev *pcidev = hba->pcidev;
hba->u.itl.iop = hptiop_map_pci_bar(hba, 0);
- if (hba->u.itl.iop)
- return 0;
- else
+ if (hba->u.itl.iop == NULL)
return -1;
+ if ((pcidev->device & 0xff00) == 0x4400) {
+ hba->u.itl.plx = hba->u.itl.iop;
+ hba->u.itl.iop = hptiop_map_pci_bar(hba, 2);
+ if (hba->u.itl.iop == NULL) {
+ iounmap(hba->u.itl.plx);
+ return -1;
+ }
+ }
+ return 0;
}
static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba)
{
+ if (hba->u.itl.plx)
+ iounmap(hba->u.itl.plx);
iounmap(hba->u.itl.iop);
}
@@ -1239,22 +1253,23 @@ static struct hptiop_adapter_ops hptiop_mv_ops = {
static struct pci_device_id hptiop_id_table[] = {
{ PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3530), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3560), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops },
- { PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4210), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4211), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4310), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x4311), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops },
+ { PCI_VDEVICE(TTI, 0x4400), (kernel_ulong_t)&hptiop_itl_ops },
{ PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops },
{ PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops },
{ PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops },
diff --git a/drivers/scsi/hptiop.h b/drivers/scsi/hptiop.h
index a0289f219752..0b871c0ae568 100644
--- a/drivers/scsi/hptiop.h
+++ b/drivers/scsi/hptiop.h
@@ -1,6 +1,6 @@
/*
* HighPoint RR3xxx/4xxx controller driver for Linux
- * Copyright (C) 2006-2007 HighPoint Technologies, Inc. All Rights Reserved.
+ * Copyright (C) 2006-2009 HighPoint Technologies, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -228,6 +228,7 @@ struct hptiop_hba {
union {
struct {
struct hpt_iopmu_itl __iomem *iop;
+ void __iomem *plx;
} itl;
struct {
struct hpt_iopmv_regs *regs;
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 2b1b834a098b..edc49ca49cea 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -811,7 +811,7 @@ iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max,
goto free_host;
cls_session = iscsi_session_setup(&iscsi_sw_tcp_transport, shost,
- cmds_max,
+ cmds_max, 0,
sizeof(struct iscsi_tcp_task) +
sizeof(struct iscsi_sw_tcp_hdrbuf),
initial_cmdsn, 0);
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 8dc73c489a17..f1a4246f890c 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -2436,7 +2436,7 @@ static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost)
*/
struct iscsi_cls_session *
iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
- uint16_t cmds_max, int cmd_task_size,
+ uint16_t cmds_max, int dd_size, int cmd_task_size,
uint32_t initial_cmdsn, unsigned int id)
{
struct iscsi_host *ihost = shost_priv(shost);
@@ -2486,7 +2486,8 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX;
cls_session = iscsi_alloc_session(shost, iscsit,
- sizeof(struct iscsi_session));
+ sizeof(struct iscsi_session) +
+ dd_size);
if (!cls_session)
goto dec_session_count;
session = cls_session->dd_data;
@@ -2503,6 +2504,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
session->max_cmdsn = initial_cmdsn + 1;
session->max_r2t = 1;
session->tt = iscsit;
+ session->dd_data = cls_session->dd_data + sizeof(*session);
mutex_init(&session->eh_mutex);
spin_lock_init(&session->lock);
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index 61d089703806..c88f59f0ce30 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -56,8 +56,6 @@ static char *dif_op_str[] = {
"SCSI_PROT_WRITE_INSERT",
"SCSI_PROT_READ_PASS",
"SCSI_PROT_WRITE_PASS",
- "SCSI_PROT_READ_CONVERT",
- "SCSI_PROT_WRITE_CONVERT"
};
static void
lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb);
@@ -1131,13 +1129,11 @@ lpfc_sc_to_sli_prof(struct scsi_cmnd *sc)
ret_prof = LPFC_PROF_A1;
break;
- case SCSI_PROT_READ_CONVERT:
- case SCSI_PROT_WRITE_CONVERT:
+ case SCSI_PROT_READ_PASS:
+ case SCSI_PROT_WRITE_PASS:
ret_prof = LPFC_PROF_AST1;
break;
- case SCSI_PROT_READ_PASS:
- case SCSI_PROT_WRITE_PASS:
case SCSI_PROT_NORMAL:
default:
printk(KERN_ERR "Bad op/guard:%d/%d combination\n",
@@ -1157,8 +1153,6 @@ lpfc_sc_to_sli_prof(struct scsi_cmnd *sc)
ret_prof = LPFC_PROF_C1;
break;
- case SCSI_PROT_READ_CONVERT:
- case SCSI_PROT_WRITE_CONVERT:
case SCSI_PROT_READ_INSERT:
case SCSI_PROT_WRITE_STRIP:
case SCSI_PROT_NORMAL:
@@ -1209,8 +1203,7 @@ lpfc_get_cmd_dif_parms(struct scsi_cmnd *sc, uint16_t *apptagmask,
static int cnt;
if (protcnt && (op == SCSI_PROT_WRITE_STRIP ||
- op == SCSI_PROT_WRITE_PASS ||
- op == SCSI_PROT_WRITE_CONVERT)) {
+ op == SCSI_PROT_WRITE_PASS)) {
cnt++;
spt = page_address(sg_page(scsi_prot_sglist(sc))) +
@@ -1501,8 +1494,6 @@ lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc)
case SCSI_PROT_WRITE_STRIP:
case SCSI_PROT_READ_PASS:
case SCSI_PROT_WRITE_PASS:
- case SCSI_PROT_WRITE_CONVERT:
- case SCSI_PROT_READ_CONVERT:
ret = LPFC_PG_TYPE_DIF_BUF;
break;
default:
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/Kconfig b/drivers/scsi/mpt2sas/Kconfig
index 4a86855c23b3..70c4c2467dd8 100644
--- a/drivers/scsi/mpt2sas/Kconfig
+++ b/drivers/scsi/mpt2sas/Kconfig
@@ -2,7 +2,7 @@
# Kernel configuration file for the MPT2SAS
#
# This code is based on drivers/scsi/mpt2sas/Kconfig
-# Copyright (C) 2007-2008 LSI Corporation
+# Copyright (C) 2007-2009 LSI Corporation
# (mailto:DL-MPTFusionLinux@lsi.com)
# This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index 7bb2ece8b2e4..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.11
+ * mpi2.h Version: 02.00.13
*
* Version History
* ---------------
@@ -45,6 +45,14 @@
* 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT.
* Moved LUN field defines from mpi2_init.h.
* 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT.
+ * In all request and reply descriptors, replaced VF_ID
+ * field with MSIxIndex field.
+ * Removed DevHandle field from
+ * 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.
* --------------------------------------------------------------------------
*/
@@ -70,7 +78,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x0B)
+#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)
@@ -257,7 +265,7 @@ typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS
typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 DescriptorTypeDependent; /* 0x06 */
@@ -271,6 +279,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02)
#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06)
#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08)
+#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A)
#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01)
@@ -279,7 +288,7 @@ typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR
typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 Reserved1; /* 0x06 */
@@ -293,7 +302,7 @@ typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR
typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 DevHandle; /* 0x06 */
@@ -306,7 +315,7 @@ typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR
typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR
{
U8 RequestFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U16 LMID; /* 0x04 */
U16 IoIndex; /* 0x06 */
@@ -315,14 +324,29 @@ typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR
Mpi2SCSITargetRequestDescriptor_t,
MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t;
+
+/* RAID Accelerator Request Descriptor */
+typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR {
+ U8 RequestFlags; /* 0x00 */
+ U8 MSIxIndex; /* 0x01 */
+ U16 SMID; /* 0x02 */
+ U16 LMID; /* 0x04 */
+ U16 Reserved; /* 0x06 */
+} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR,
+ MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR,
+ Mpi2RAIDAcceleratorRequestDescriptor_t,
+ MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_t;
+
+
/* union of Request Descriptors */
typedef union _MPI2_REQUEST_DESCRIPTOR_UNION
{
- MPI2_DEFAULT_REQUEST_DESCRIPTOR Default;
- MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority;
- MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO;
- MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget;
- U64 Words;
+ MPI2_DEFAULT_REQUEST_DESCRIPTOR Default;
+ MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority;
+ MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO;
+ MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget;
+ MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator;
+ U64 Words;
} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION,
Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t;
@@ -333,19 +357,20 @@ typedef union _MPI2_REQUEST_DESCRIPTOR_UNION
typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 DescriptorTypeDependent1; /* 0x02 */
U32 DescriptorTypeDependent2; /* 0x04 */
} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR,
Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t;
/* defines for the ReplyFlags field */
-#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F)
-#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00)
-#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01)
-#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02)
-#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03)
-#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F)
+#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F)
+#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00)
+#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01)
+#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02)
+#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03)
+#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05)
+#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F)
/* values for marking a reply descriptor as unused */
#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF)
@@ -355,7 +380,7 @@ typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR
typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U32 ReplyFrameAddress; /* 0x04 */
} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR,
@@ -368,10 +393,10 @@ typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR
typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U16 TaskTag; /* 0x04 */
- U16 DevHandle; /* 0x06 */
+ U16 Reserved1; /* 0x06 */
} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR,
Mpi2SCSIIOSuccessReplyDescriptor_t,
@@ -382,7 +407,7 @@ typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR
typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U16 SMID; /* 0x02 */
U8 SequenceNumber; /* 0x04 */
U8 Reserved1; /* 0x05 */
@@ -397,7 +422,7 @@ typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR
typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR
{
U8 ReplyFlags; /* 0x00 */
- U8 VF_ID; /* 0x01 */
+ U8 MSIxIndex; /* 0x01 */
U8 VP_ID; /* 0x02 */
U8 Flags; /* 0x03 */
U16 InitiatorDevHandle; /* 0x04 */
@@ -411,15 +436,28 @@ typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR
#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F)
+/* RAID Accelerator Success Reply Descriptor */
+typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR {
+ U8 ReplyFlags; /* 0x00 */
+ U8 MSIxIndex; /* 0x01 */
+ U16 SMID; /* 0x02 */
+ U32 Reserved; /* 0x04 */
+} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR,
+ MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR,
+ Mpi2RAIDAcceleratorSuccessReplyDescriptor_t,
+ MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t;
+
+
/* union of Reply Descriptors */
typedef union _MPI2_REPLY_DESCRIPTORS_UNION
{
- MPI2_DEFAULT_REPLY_DESCRIPTOR Default;
- MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply;
- MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess;
- MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess;
- MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
- U64 Words;
+ MPI2_DEFAULT_REPLY_DESCRIPTOR Default;
+ MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply;
+ MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess;
+ MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess;
+ MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer;
+ MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess;
+ U64 Words;
} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION,
Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t;
@@ -458,6 +496,7 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) /* Diagnostic Release */
#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */
#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */
+#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/
@@ -555,12 +594,17 @@ typedef union _MPI2_REPLY_DESCRIPTORS_UNION
#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0)
+/****************************************************************************
+* RAID Accelerator values
+****************************************************************************/
+
+#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0)
/****************************************************************************
* IOCStatus flag to indicate that log info is available
****************************************************************************/
-#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000)
+#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000)
/****************************************************************************
* IOCLogInfo Types
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index 2f27cf6d6c65..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.10
+ * mpi2_cnfg.h Version: 02.00.12
*
* Version History
* ---------------
@@ -95,6 +95,18 @@
* Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define.
* Added PortGroups, DmaGroup, and ControlGroup fields to
* SAS Device Page 0.
+ * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO
+ * Unit Page 6.
+ * 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.
* --------------------------------------------------------------------------
*/
@@ -177,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)
/*****************************************************************************
@@ -263,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
****************************************************************************/
@@ -344,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 */
@@ -723,6 +753,115 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3
#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON (0x0001)
+/* IO Unit Page 5 */
+
+/*
+ * Upper layer code (drivers, utilities, etc.) should leave this define set to
+ * one and check Header.PageLength or NumDmaEngines at runtime.
+ */
+#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES
+#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 {
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U64 RaidAcceleratorBufferBaseAddress; /* 0x04 */
+ U64 RaidAcceleratorBufferSize; /* 0x0C */
+ U64 RaidAcceleratorControlBaseAddress; /* 0x14 */
+ U8 RAControlSize; /* 0x1C */
+ U8 NumDmaEngines; /* 0x1D */
+ U8 RAMinControlSize; /* 0x1E */
+ U8 RAMaxControlSize; /* 0x1F */
+ U32 Reserved1; /* 0x20 */
+ U32 Reserved2; /* 0x24 */
+ U32 Reserved3; /* 0x28 */
+ U32 DmaEngineCapabilities
+ [MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /* 0x2C */
+} MPI2_CONFIG_PAGE_IO_UNIT_5, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_5,
+ Mpi2IOUnitPage5_t, MPI2_POINTER pMpi2IOUnitPage5_t;
+
+#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00)
+
+/* defines for IO Unit Page 5 DmaEngineCapabilities field */
+#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFF00)
+#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16)
+
+#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008)
+#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004)
+#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002)
+#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001)
+
+
+/* IO Unit Page 6 */
+
+typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 {
+ MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
+ U16 Flags; /* 0x04 */
+ U8 RAHostControlSize; /* 0x06 */
+ U8 Reserved0; /* 0x07 */
+ U64 RaidAcceleratorHostControlBaseAddress; /* 0x08 */
+ U32 Reserved1; /* 0x10 */
+ U32 Reserved2; /* 0x14 */
+ U32 Reserved3; /* 0x18 */
+} MPI2_CONFIG_PAGE_IO_UNIT_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_6,
+ Mpi2IOUnitPage6_t, MPI2_POINTER pMpi2IOUnitPage6_t;
+
+#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00)
+
+/* defines for IO Unit Page 6 Flags field */
+#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
****************************************************************************/
@@ -1406,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)
@@ -1618,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)
@@ -1681,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
****************************************************************************/
@@ -1709,10 +1922,14 @@ typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0
U64 ActiveZoneManagerSASAddress;/* 0x2C */
U16 ZoneLockInactivityLimit; /* 0x34 */
U16 Reserved1; /* 0x36 */
+ U8 TimeToReducedFunc; /* 0x38 */
+ U8 InitialTimeToReducedFunc; /* 0x39 */
+ U8 MaxReducedFuncTime; /* 0x3A */
+ U8 Reserved2; /* 0x3B */
} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0,
Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t;
-#define MPI2_SASEXPANDER0_PAGEVERSION (0x05)
+#define MPI2_SASEXPANDER0_PAGEVERSION (0x06)
/* values for SAS Expander Page 0 DiscoveryStatus field */
#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000)
@@ -1737,6 +1954,7 @@ typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0
#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001)
/* values for SAS Expander Page 0 Flags field */
+#define MPI2_SAS_EXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000)
#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED (0x1000)
#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800)
#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400)
@@ -1858,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)
@@ -1944,6 +2164,133 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1
#define MPI2_SASPHY1_PAGEVERSION (0x01)
+/* SAS PHY Page 2 */
+
+typedef struct _MPI2_SASPHY2_PHY_EVENT {
+ U8 PhyEventCode; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U32 PhyEventInfo; /* 0x04 */
+} MPI2_SASPHY2_PHY_EVENT, MPI2_POINTER PTR_MPI2_SASPHY2_PHY_EVENT,
+ Mpi2SasPhy2PhyEvent_t, MPI2_POINTER pMpi2SasPhy2PhyEvent_t;
+
+/* use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */
+
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ */
+#ifndef MPI2_SASPHY2_PHY_EVENT_MAX
+#define MPI2_SASPHY2_PHY_EVENT_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U8 NumPhyEvents; /* 0x0C */
+ U8 Reserved2; /* 0x0D */
+ U16 Reserved3; /* 0x0E */
+ MPI2_SASPHY2_PHY_EVENT PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX];
+ /* 0x10 */
+} MPI2_CONFIG_PAGE_SAS_PHY_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_2,
+ Mpi2SasPhyPage2_t, MPI2_POINTER pMpi2SasPhyPage2_t;
+
+#define MPI2_SASPHY2_PAGEVERSION (0x00)
+
+
+/* SAS PHY Page 3 */
+
+typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG {
+ U8 PhyEventCode; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U16 Reserved2; /* 0x02 */
+ U8 CounterType; /* 0x04 */
+ U8 ThresholdWindow; /* 0x05 */
+ U8 TimeUnits; /* 0x06 */
+ U8 Reserved3; /* 0x07 */
+ U32 EventThreshold; /* 0x08 */
+ U16 ThresholdFlags; /* 0x0C */
+ U16 Reserved4; /* 0x0E */
+} MPI2_SASPHY3_PHY_EVENT_CONFIG, MPI2_POINTER PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG,
+ Mpi2SasPhy3PhyEventConfig_t, MPI2_POINTER pMpi2SasPhy3PhyEventConfig_t;
+
+/* values for PhyEventCode field */
+#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00)
+#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01)
+#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02)
+#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03)
+#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04)
+#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05)
+#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06)
+#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20)
+#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22)
+#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23)
+#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26)
+#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27)
+#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28)
+#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29)
+#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A)
+#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B)
+#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C)
+#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D)
+#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43)
+#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44)
+#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51)
+#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52)
+#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61)
+#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63)
+#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0)
+#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1)
+#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2)
+
+/* values for the CounterType field */
+#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00)
+#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01)
+#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02)
+
+/* values for the TimeUnits field */
+#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00)
+#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01)
+#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02)
+#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03)
+
+/* values for the ThresholdFlags field */
+#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002)
+#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001)
+
+/*
+ * Host code (drivers, BIOS, utilities, etc.) should leave this define set to
+ * one and check Header.ExtPageLength or NumPhyEvents at runtime.
+ */
+#ifndef MPI2_SASPHY3_PHY_EVENT_MAX
+#define MPI2_SASPHY3_PHY_EVENT_MAX (1)
+#endif
+
+typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 {
+ MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U8 NumPhyEvents; /* 0x0C */
+ U8 Reserved2; /* 0x0D */
+ U16 Reserved3; /* 0x0E */
+ MPI2_SASPHY3_PHY_EVENT_CONFIG PhyEventConfig
+ [MPI2_SASPHY3_PHY_EVENT_MAX]; /* 0x10 */
+} MPI2_CONFIG_PAGE_SAS_PHY_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_3,
+ Mpi2SasPhyPage3_t, MPI2_POINTER pMpi2SasPhyPage3_t;
+
+#define MPI2_SASPHY3_PAGEVERSION (0x00)
+
+
/****************************************************************************
* SAS Port Config Pages
****************************************************************************/
@@ -2147,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_history.txt b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
new file mode 100644
index 000000000000..65fcaa31cb30
--- /dev/null
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_history.txt
@@ -0,0 +1,334 @@
+ ==============================
+ Fusion-MPT MPI 2.0 Header File Change History
+ ==============================
+
+ Copyright (c) 2000-2009 LSI Corporation.
+
+ ---------------------------------------
+ Header Set Release Version: 02.00.12
+ Header Set Release Date: 05-06-09
+ ---------------------------------------
+
+ Filename Current version Prior version
+ ---------- --------------- -------------
+ mpi2.h 02.00.12 02.00.11
+ mpi2_cnfg.h 02.00.11 02.00.10
+ mpi2_init.h 02.00.07 02.00.06
+ mpi2_ioc.h 02.00.11 02.00.10
+ mpi2_raid.h 02.00.03 02.00.03
+ mpi2_sas.h 02.00.02 02.00.02
+ mpi2_targ.h 02.00.03 02.00.03
+ mpi2_tool.h 02.00.03 02.00.02
+ mpi2_type.h 02.00.00 02.00.00
+ mpi2_ra.h 02.00.00
+ mpi2_history.txt 02.00.11 02.00.12
+
+
+ * Date Version Description
+ * -------- -------- ------------------------------------------------------
+
+mpi2.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Moved ReplyPostHostIndex register to offset 0x6C of the
+ * MPI2_SYSTEM_INTERFACE_REGS and modified the define for
+ * MPI2_REPLY_POST_HOST_INDEX_OFFSET.
+ * Added union of request descriptors.
+ * Added union of reply descriptors.
+ * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added define for MPI2_VERSION_02_00.
+ * Fixed the size of the FunctionDependent5 field in the
+ * MPI2_DEFAULT_REPLY structure.
+ * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Removed the MPI-defined Fault Codes and extended the
+ * product specific codes up to 0xEFFF.
+ * Added a sixth key value for the WriteSequence register
+ * and changed the flush value to 0x0.
+ * Added message function codes for Diagnostic Buffer Post
+ * and Diagnsotic Release.
+ * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED
+ * Moved MPI2_VERSION_UNION from mpi2_ioc.h.
+ * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Added #defines for marking a reply descriptor as unused.
+ * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT.
+ * Moved LUN field defines from mpi2_init.h.
+ * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT.
+ * In all request and reply descriptors, replaced VF_ID
+ * field with MSIxIndex field.
+ * Removed DevHandle field from
+ * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those
+ * bytes reserved.
+ * Added RAID Accelerator functionality.
+ * --------------------------------------------------------------------------
+
+mpi2_cnfg.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags.
+ * Added Manufacturing Page 11.
+ * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE
+ * define.
+ * 06-26-07 02.00.02 Adding generic structure for product-specific
+ * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS.
+ * Rework of BIOS Page 2 configuration page.
+ * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the
+ * forms.
+ * Added configuration pages IOC Page 8 and Driver
+ * Persistent Mapping Page 0.
+ * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated
+ * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1,
+ * RAID Physical Disk Pages 0 and 1, RAID Configuration
+ * Page 0).
+ * Added new value for AccessStatus field of SAS Device
+ * Page 0 (_SATA_NEEDS_INITIALIZATION).
+ * 10-31-07 02.00.04 Added missing SEPDevHandle field to
+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
+ * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for
+ * NVDATA.
+ * Modified IOC Page 7 to use masks and added field for
+ * SASBroadcastPrimitiveMasks.
+ * Added MPI2_CONFIG_PAGE_BIOS_4.
+ * Added MPI2_CONFIG_PAGE_LOG_0.
+ * 02-29-08 02.00.06 Modified various names to make them 32-character unique.
+ * Added SAS Device IDs.
+ * Updated Integrated RAID configuration pages including
+ * Manufacturing Page 4, IOC Page 6, and RAID Configuration
+ * Page 0.
+ * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA.
+ * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION.
+ * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING.
+ * Added missing MaxNumRoutedSasAddresses field to
+ * MPI2_CONFIG_PAGE_EXPANDER_0.
+ * Added SAS Port Page 0.
+ * Modified structure layout for
+ * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0.
+ * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use
+ * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array.
+ * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF
+ * to 0x000000FF.
+ * Added two new values for the Physical Disk Coercion Size
+ * bits in the Flags field of Manufacturing Page 4.
+ * Added product-specific Manufacturing pages 16 to 31.
+ * Modified Flags bits for controlling write cache on SATA
+ * drives in IO Unit Page 1.
+ * Added new bit to AdditionalControlFlags of SAS IO Unit
+ * Page 1 to control Invalid Topology Correction.
+ * Added SupportedPhysDisks field to RAID Volume Page 1 and
+ * added related defines.
+ * Added additional defines for RAID Volume Page 0
+ * VolumeStatusFlags field.
+ * Modified meaning of RAID Volume Page 0 VolumeSettings
+ * define for auto-configure of hot-swap drives.
+ * Added PhysDiskAttributes field (and related defines) to
+ * RAID Physical Disk Page 0.
+ * Added MPI2_SAS_PHYINFO_PHY_VACANT define.
+ * Added three new DiscoveryStatus bits for SAS IO Unit
+ * Page 0 and SAS Expander Page 0.
+ * Removed multiplexing information from SAS IO Unit pages.
+ * Added BootDeviceWaitTime field to SAS IO Unit Page 4.
+ * Removed Zone Address Resolved bit from PhyInfo and from
+ * Expander Page 0 Flags field.
+ * Added two new AccessStatus values to SAS Device Page 0
+ * for indicating routing problems. Added 3 reserved words
+ * to this page.
+ * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3.
+ * Inserted missing reserved field into structure for IOC
+ * Page 6.
+ * Added more pending task bits to RAID Volume Page 0
+ * VolumeStatusFlags defines.
+ * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define.
+ * Added a new DiscoveryStatus bit for SAS IO Unit Page 0
+ * and SAS Expander Page 0 to flag a downstream initiator
+ * when in simplified routing mode.
+ * Removed SATA Init Failure defines for DiscoveryStatus
+ * fields of SAS IO Unit Page 0 and SAS Expander Page 0.
+ * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define.
+ * Added PortGroups, DmaGroup, and ControlGroup fields to
+ * SAS Device Page 0.
+ * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO
+ * Unit Page 6.
+ * Added expander reduced functionality data to SAS
+ * Expander Page 0.
+ * Added SAS PHY Page 2 and SAS PHY Page 3.
+ * --------------------------------------------------------------------------
+
+mpi2_init.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t.
+ * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines.
+ * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention.
+ * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY.
+ * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t.
+ * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO
+ * Control field Task Attribute flags.
+ * Moved LUN field defines to mpi2.h becasue they are
+ * common to many structures.
+ * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to
+ * Query Asynchronous Event.
+ * Defined two new bits in the SlotStatus field of the SCSI
+ * Enclosure Processor Request and Reply.
+ * --------------------------------------------------------------------------
+
+mpi2_ioc.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to
+ * MaxTargets.
+ * Added TotalImageSize field to FWDownload Request.
+ * Added reserved words to FWUpload Request.
+ * 06-26-07 02.00.02 Added IR Configuration Change List Event.
+ * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit
+ * request and replaced it with
+ * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth.
+ * Replaced the MinReplyQueueDepth field of the IOCFacts
+ * reply with MaxReplyDescriptorPostQueueDepth.
+ * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum
+ * depth for the Reply Descriptor Post Queue.
+ * Added SASAddress field to Initiator Device Table
+ * Overflow Event data.
+ * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING
+ * for SAS Initiator Device Status Change Event data.
+ * Modified Reason Code defines for SAS Topology Change
+ * List Event data, including adding a bit for PHY Vacant
+ * status, and adding a mask for the Reason Code.
+ * Added define for
+ * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING.
+ * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID.
+ * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of
+ * the IOCFacts Reply.
+ * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define.
+ * Moved MPI2_VERSION_UNION to mpi2.h.
+ * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks
+ * instead of enables, and added SASBroadcastPrimitiveMasks
+ * field.
+ * Added Log Entry Added Event and related structure.
+ * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID.
+ * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET.
+ * Added MaxVolumes and MaxPersistentEntries fields to
+ * IOCFacts reply.
+ * Added ProtocalFlags and IOCCapabilities fields to
+ * MPI2_FW_IMAGE_HEADER.
+ * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT.
+ * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to
+ * a U16 (from a U32).
+ * Removed extra 's' from EventMasks name.
+ * 06-27-08 02.00.08 Fixed an offset in a comment.
+ * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST.
+ * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and
+ * renamed MinReplyFrameSize to ReplyFrameSize.
+ * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX.
+ * Added two new RAIDOperation values for Integrated RAID
+ * Operations Status Event data.
+ * Added four new IR Configuration Change List Event data
+ * ReasonCode values.
+ * Added two new ReasonCode defines for SAS Device Status
+ * Change Event data.
+ * Added three new DiscoveryStatus bits for the SAS
+ * Discovery event data.
+ * Added Multiplexing Status Change bit to the PhyStatus
+ * field of the SAS Topology Change List event data.
+ * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY.
+ * BootFlags are now product-specific.
+ * Added defines for the indivdual signature bytes
+ * for MPI2_INIT_IMAGE_FOOTER.
+ * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define.
+ * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR
+ * define.
+ * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE
+ * define.
+ * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define.
+ * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define.
+ * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define.
+ * Added two new reason codes for SAS Device Status Change
+ * Event.
+ * Added new event: SAS PHY Counter.
+ * --------------------------------------------------------------------------
+
+mpi2_raid.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 08-31-07 02.00.01 Modifications to RAID Action request and reply,
+ * including the Actions and ActionData.
+ * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD.
+ * 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.
+ * --------------------------------------------------------------------------
+
+mpi2_sas.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit
+ * Control Request.
+ * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control
+ * Request.
+ * --------------------------------------------------------------------------
+
+mpi2_targ.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 08-31-07 02.00.01 Added Command Buffer Data Location Address Space bits to
+ * BufferPostFlags field of CommandBufferPostBase Request.
+ * 02-29-08 02.00.02 Modified various names to make them 32-character unique.
+ * 10-02-08 02.00.03 Removed NextCmdBufferOffset from
+ * MPI2_TARGET_CMD_BUF_POST_BASE_REQUEST.
+ * Target Status Send Request only takes a single SGE for
+ * response data.
+ * --------------------------------------------------------------------------
+
+mpi2_tool.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release
+ * 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.
+ * --------------------------------------------------------------------------
+
+mpi2_type.h
+ * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A.
+ * --------------------------------------------------------------------------
+
+mpi2_ra.h
+ * 05-06-09 02.00.00 Initial version.
+ * --------------------------------------------------------------------------
+
+mpi2_history.txt Parts list history
+
+Filename 02.00.12
+---------- --------
+mpi2.h 02.00.12
+mpi2_cnfg.h 02.00.11
+mpi2_init.h 02.00.07
+mpi2_ioc.h 02.00.11
+mpi2_raid.h 02.00.03
+mpi2_sas.h 02.00.02
+mpi2_targ.h 02.00.03
+mpi2_tool.h 02.00.03
+mpi2_type.h 02.00.00
+mpi2_ra.h 02.00.00
+
+Filename 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06
+---------- -------- -------- -------- -------- -------- --------
+mpi2.h 02.00.11 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06
+mpi2_cnfg.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.06 02.00.06
+mpi2_init.h 02.00.06 02.00.06 02.00.05 02.00.05 02.00.04 02.00.03
+mpi2_ioc.h 02.00.10 02.00.09 02.00.08 02.00.07 02.00.07 02.00.06
+mpi2_raid.h 02.00.03 02.00.03 02.00.03 02.00.03 02.00.02 02.00.02
+mpi2_sas.h 02.00.02 02.00.02 02.00.01 02.00.01 02.00.01 02.00.01
+mpi2_targ.h 02.00.03 02.00.03 02.00.02 02.00.02 02.00.02 02.00.02
+mpi2_tool.h 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02 02.00.02
+mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+
+Filename 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+---------- -------- -------- -------- -------- -------- --------
+mpi2.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+mpi2_cnfg.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+mpi2_init.h 02.00.02 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_ioc.h 02.00.05 02.00.04 02.00.03 02.00.02 02.00.01 02.00.00
+mpi2_raid.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00
+mpi2_sas.h 02.00.01 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00
+mpi2_targ.h 02.00.01 02.00.01 02.00.01 02.00.00 02.00.00 02.00.00
+mpi2_tool.h 02.00.01 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+mpi2_type.h 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00 02.00.00
+
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
index f1115f0f0eb2..563e56d2e945 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_init.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_init.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2008 LSI Corporation.
+ * Copyright (c) 2000-2009 LSI Corporation.
*
*
* Name: mpi2_init.h
* Title: MPI SCSI initiator mode messages and structures
* Creation Date: June 23, 2006
*
- * mpi2_init.h Version: 02.00.06
+ * mpi2_init.h Version: 02.00.07
*
* Version History
* ---------------
@@ -23,6 +23,10 @@
* Control field Task Attribute flags.
* Moved LUN field defines to mpi2.h becasue they are
* common to many structures.
+ * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to
+ * Query Asynchronous Event.
+ * Defined two new bits in the SlotStatus field of the SCSI
+ * Enclosure Processor Request and Reply.
* --------------------------------------------------------------------------
*/
@@ -289,7 +293,11 @@ typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST
#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07)
#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08)
#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09)
-#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION (0x0A)
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A)
+
+/* obsolete TaskType name */
+#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION \
+ (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT)
/* MsgFlags bits */
@@ -375,6 +383,8 @@ typedef struct _MPI2_SEP_REQUEST
#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100)
#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080)
#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040)
+#define MPI2_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010)
+#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008)
#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004)
#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002)
#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001)
@@ -410,6 +420,8 @@ typedef struct _MPI2_SEP_REPLY
#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100)
#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080)
#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040)
+#define MPI2_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010)
+#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008)
#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004)
#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002)
#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index 8c5d81870c03..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.10
+ * mpi2_ioc.h Version: 02.00.12
*
* Version History
* ---------------
@@ -79,6 +79,14 @@
* Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE
* define.
* Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define.
+ * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define.
+ * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define.
+ * 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.
* --------------------------------------------------------------------------
*/
@@ -261,12 +269,15 @@ typedef struct _MPI2_IOC_FACTS_REPLY
/* ProductID field uses MPI2_FW_HEADER_PID_ */
/* IOCCapabilities */
+#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000)
+#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000)
#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000)
#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID (0x00001000)
#define MPI2_IOCFACTS_CAPABILITY_TLR (0x00000800)
#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)
@@ -440,6 +451,8 @@ typedef struct _MPI2_EVENT_NOTIFICATION_REPLY
#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F)
#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 */
@@ -461,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
@@ -502,17 +525,19 @@ typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE
MPI2_POINTER pMpi2EventDataSasDeviceStatusChange_t;
/* SAS Device Status Change Event data ReasonCode values */
-#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F)
-#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11)
+#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12)
/* Integrated RAID Operation Status Event data */
@@ -822,6 +847,37 @@ typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE
#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02)
+/* SAS PHY Counter Event data */
+
+typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER {
+ U64 TimeStamp; /* 0x00 */
+ U32 Reserved1; /* 0x08 */
+ U8 PhyEventCode; /* 0x0C */
+ U8 PhyNum; /* 0x0D */
+ U16 Reserved2; /* 0x0E */
+ U32 PhyEventInfo; /* 0x10 */
+ U8 CounterType; /* 0x14 */
+ U8 ThresholdWindow; /* 0x15 */
+ U8 TimeUnits; /* 0x16 */
+ U8 Reserved3; /* 0x17 */
+ U32 EventThreshold; /* 0x18 */
+ U16 ThresholdFlags; /* 0x1C */
+ U16 Reserved4; /* 0x1E */
+} MPI2_EVENT_DATA_SAS_PHY_COUNTER,
+ MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER,
+ Mpi2EventDataSasPhyCounter_t, MPI2_POINTER pMpi2EventDataSasPhyCounter_t;
+
+/* use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h for the
+ * PhyEventCode field
+ * use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h for the
+ * CounterType field
+ * use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h for the
+ * TimeUnits field
+ * use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the
+ * ThresholdFlags field
+ * */
+
+
/****************************************************************************
* EventAck message
****************************************************************************/
@@ -1076,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 2ff4e936bd39..73fcdbf92632 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
@@ -1,12 +1,12 @@
/*
- * Copyright (c) 2000-2008 LSI Corporation.
+ * Copyright (c) 2000-2009 LSI Corporation.
*
*
* Name: mpi2_tool.h
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.02
+ * mpi2_tool.h Version: 02.00.04
*
* Version History
* ---------------
@@ -17,6 +17,11 @@
* 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release
* 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.
* --------------------------------------------------------------------------
*/
@@ -32,7 +37,10 @@
/* defines for the Tools */
#define MPI2_TOOLBOX_CLEAN_TOOL (0x00)
#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01)
+#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03)
#define MPI2_TOOLBOX_BEACON_TOOL (0x05)
+#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06)
+
/****************************************************************************
* Toolbox reply
@@ -112,6 +120,77 @@ typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST
/****************************************************************************
+* Toolbox ISTWI Read Write Tool
+****************************************************************************/
+
+/* Toolbox ISTWI Read Write Tool request message */
+typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST {
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U32 Reserved5; /* 0x0C */
+ U32 Reserved6; /* 0x10 */
+ U8 DevIndex; /* 0x14 */
+ U8 Action; /* 0x15 */
+ U8 SGLFlags; /* 0x16 */
+ U8 Reserved7; /* 0x17 */
+ U16 TxDataLength; /* 0x18 */
+ U16 RxDataLength; /* 0x1A */
+ U32 Reserved8; /* 0x1C */
+ U32 Reserved9; /* 0x20 */
+ U32 Reserved10; /* 0x24 */
+ U32 Reserved11; /* 0x28 */
+ U32 Reserved12; /* 0x2C */
+ MPI2_SGE_SIMPLE_UNION SGL; /* 0x30 */
+} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST,
+ Mpi2ToolboxIstwiReadWriteRequest_t,
+ MPI2_POINTER pMpi2ToolboxIstwiReadWriteRequest_t;
+
+/* values for the Action field */
+#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01)
+#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02)
+#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03)
+#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10)
+#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11)
+#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12)
+
+/* values for SGLFlags field are in the SGL section of mpi2.h */
+
+
+/* Toolbox ISTWI Read Write Tool reply message */
+typedef struct _MPI2_TOOLBOX_ISTWI_REPLY {
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 MsgLength; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U16 Reserved5; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+ U8 DevIndex; /* 0x14 */
+ U8 Action; /* 0x15 */
+ U8 IstwiStatus; /* 0x16 */
+ U8 Reserved6; /* 0x17 */
+ U16 TxDataCount; /* 0x18 */
+ U16 RxDataCount; /* 0x1A */
+} MPI2_TOOLBOX_ISTWI_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_REPLY,
+ Mpi2ToolboxIstwiReply_t, MPI2_POINTER pMpi2ToolboxIstwiReply_t;
+
+
+/****************************************************************************
* Toolbox Beacon Tool request
****************************************************************************/
@@ -139,6 +218,61 @@ typedef struct _MPI2_TOOLBOX_BEACON_REQUEST
#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01)
+/****************************************************************************
+* Toolbox Diagnostic CLI Tool
+****************************************************************************/
+
+#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C)
+
+/* Toolbox Diagnostic CLI Tool request message */
+typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST {
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 ChainOffset; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U8 SGLFlags; /* 0x0C */
+ U8 Reserved5; /* 0x0D */
+ U16 Reserved6; /* 0x0E */
+ U32 DataLength; /* 0x10 */
+ U8 DiagnosticCliCommand
+ [MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */
+ MPI2_SGE_SIMPLE_UNION SGL; /* 0x70 */
+} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST,
+ Mpi2ToolboxDiagnosticCliRequest_t,
+ MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t;
+
+/* values for SGLFlags field are in the SGL section of mpi2.h */
+
+
+/* Toolbox Diagnostic CLI Tool reply message */
+typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY {
+ U8 Tool; /* 0x00 */
+ U8 Reserved1; /* 0x01 */
+ U8 MsgLength; /* 0x02 */
+ U8 Function; /* 0x03 */
+ U16 Reserved2; /* 0x04 */
+ U8 Reserved3; /* 0x06 */
+ U8 MsgFlags; /* 0x07 */
+ U8 VP_ID; /* 0x08 */
+ U8 VF_ID; /* 0x09 */
+ U16 Reserved4; /* 0x0A */
+ U16 Reserved5; /* 0x0C */
+ U16 IOCStatus; /* 0x0E */
+ U32 IOCLogInfo; /* 0x10 */
+ U32 ReturnedDataLength; /* 0x14 */
+} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY,
+ MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY,
+ Mpi2ToolboxDiagnosticCliReply_t,
+ MPI2_POINTER pMpi2ToolboxDiagnosticCliReply_t;
+
+
/*****************************************************************************
*
* Diagnostic Buffer Messages
@@ -152,7 +286,7 @@ typedef struct _MPI2_TOOLBOX_BEACON_REQUEST
typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST
{
- U8 Reserved1; /* 0x00 */
+ U8 ExtendedType; /* 0x00 */
U8 BufferType; /* 0x01 */
U8 ChainOffset; /* 0x02 */
U8 Function; /* 0x03 */
@@ -171,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)
/****************************************************************************
@@ -184,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 d95d2f274cb3..6422e258fd52 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -3,7 +3,7 @@
* for access to MPT (Message Passing Technology) firmware.
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -57,13 +57,14 @@
#include <linux/dma-mapping.h>
#include <linux/sort.h>
#include <linux/io.h>
+#include <linux/time.h>
#include "mpt2sas_base.h"
static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS];
#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */
-#define MPT2SAS_MAX_REQUEST_QUEUE 500 /* maximum controller queue depth */
+#define MPT2SAS_MAX_REQUEST_QUEUE 600 /* maximum controller queue depth */
static int max_queue_depth = -1;
module_param(max_queue_depth, int, 0);
@@ -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,30 +610,16 @@ _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
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
* Return nothing.
*/
static void
-_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
@@ -570,24 +640,26 @@ _base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
/**
* mpt2sas_base_done - base internal command completion routine
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+u8
+mpt2sas_base_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 (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK)
- return;
+ return 1;
if (ioc->base_cmds.status == MPT2_CMD_NOT_USED)
- return;
+ return 1;
ioc->base_cmds.status |= MPT2_CMD_COMPLETE;
if (mpi_reply) {
@@ -596,18 +668,20 @@ mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
}
ioc->base_cmds.status &= ~MPT2_CMD_PENDING;
complete(&ioc->base_cmds.done);
+ return 1;
}
/**
* _base_async_event - main callback handler for firmware asyn events
- * @ioc: pointer to scsi command object
- * @VF_ID: virtual function id
+ * @ioc: per adapter object
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-static void
-_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
+static u8
+_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply)
{
Mpi2EventNotificationReply_t *mpi_reply;
Mpi2EventAckRequest_t *ack_request;
@@ -615,9 +689,9 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (!mpi_reply)
- return;
+ return 1;
if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION)
- return;
+ return 1;
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
_base_display_event_data(ioc, mpi_reply);
#endif
@@ -635,21 +709,52 @@ _base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
ack_request->Function = MPI2_FUNCTION_EVENT_ACK;
ack_request->Event = mpi_reply->Event;
ack_request->EventContext = mpi_reply->EventContext;
- ack_request->VF_ID = VF_ID;
- mpt2sas_base_put_smid_default(ioc, smid, VF_ID);
+ ack_request->VF_ID = 0; /* TODO */
+ ack_request->VP_ID = 0;
+ mpt2sas_base_put_smid_default(ioc, smid);
out:
/* scsih callback handler */
- mpt2sas_scsih_event_callback(ioc, VF_ID, reply);
+ mpt2sas_scsih_event_callback(ioc, msix_index, reply);
/* ctl callback handler */
- mpt2sas_ctl_event_callback(ioc, VF_ID, reply);
+ mpt2sas_ctl_event_callback(ioc, msix_index, reply);
+
+ return 1;
+}
+
+/**
+ * _base_get_cb_idx - obtain the callback index
+ * @ioc: per adapter object
+ * @smid: system request message index
+ *
+ * Return callback index.
+ */
+static u8
+_base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid)
+{
+ int i;
+ u8 cb_idx = 0xFF;
+
+ if (smid >= ioc->hi_priority_smid) {
+ if (smid < ioc->internal_smid) {
+ i = smid - ioc->hi_priority_smid;
+ cb_idx = ioc->hpr_lookup[i].cb_idx;
+ } else {
+ i = smid - ioc->internal_smid;
+ cb_idx = ioc->internal_lookup[i].cb_idx;
+ }
+ } else {
+ i = smid - 1;
+ cb_idx = ioc->scsi_lookup[i].cb_idx;
+ }
+ return cb_idx;
}
/**
* _base_mask_interrupts - disable interrupts
- * @ioc: pointer to scsi command object
+ * @ioc: per adapter object
*
* Disabling ResetIRQ, Reply and Doorbell Interrupts
*
@@ -669,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
*
@@ -680,7 +785,6 @@ _base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc)
{
u32 him_register;
- writel(0, &ioc->chip->HostInterruptStatus);
him_register = readl(&ioc->chip->HostInterruptMask);
him_register &= ~MPI2_HIM_RIM;
writel(him_register, &ioc->chip->HostInterruptMask);
@@ -712,9 +816,10 @@ _base_interrupt(int irq, void *bus_id)
u16 smid;
u8 cb_idx;
u32 reply;
- u8 VF_ID;
+ u8 msix_index;
struct MPT2SAS_ADAPTER *ioc = bus_id;
Mpi2ReplyDescriptorsUnion_t *rpf;
+ u8 rc;
if (ioc->mask_interrupts)
return IRQ_NONE;
@@ -733,7 +838,7 @@ _base_interrupt(int irq, void *bus_id)
reply = 0;
cb_idx = 0xFF;
smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1);
- VF_ID = rpf->Default.VF_ID;
+ msix_index = rpf->Default.MSIxIndex;
if (request_desript_type ==
MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) {
reply = le32_to_cpu
@@ -745,16 +850,18 @@ _base_interrupt(int irq, void *bus_id)
MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS)
goto next;
if (smid)
- cb_idx = ioc->scsi_lookup[smid - 1].cb_idx;
+ cb_idx = _base_get_cb_idx(ioc, smid);
if (smid && cb_idx != 0xFF) {
- mpt_callbacks[cb_idx](ioc, smid, VF_ID, reply);
+ rc = mpt_callbacks[cb_idx](ioc, smid, msix_index,
+ reply);
if (reply)
- _base_display_reply_info(ioc, smid, VF_ID,
+ _base_display_reply_info(ioc, smid, msix_index,
reply);
- mpt2sas_base_free_smid(ioc, smid);
+ if (rc)
+ mpt2sas_base_free_smid(ioc, smid);
}
if (!smid)
- _base_async_event(ioc, VF_ID, reply);
+ _base_async_event(ioc, msix_index, reply);
/* reply free queue handling */
if (reply) {
@@ -1191,19 +1298,6 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc)
}
/**
- * mpt2sas_base_get_msg_frame_dma - obtain request mf pointer phys addr
- * @ioc: per adapter object
- * @smid: system request message index(smid zero is invalid)
- *
- * Returns phys pointer to message frame.
- */
-dma_addr_t
-mpt2sas_base_get_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- return ioc->request_dma + (smid * ioc->request_sz);
-}
-
-/**
* mpt2sas_base_get_msg_frame - obtain request mf pointer
* @ioc: per adapter object
* @smid: system request message index(smid zero is invalid)
@@ -1234,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));
}
/**
@@ -1258,7 +1353,7 @@ mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr)
}
/**
- * mpt2sas_base_get_smid - obtain a free smid
+ * mpt2sas_base_get_smid - obtain a free smid from internal queue
* @ioc: per adapter object
* @cb_idx: callback index
*
@@ -1272,6 +1367,39 @@ mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)
u16 smid;
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ if (list_empty(&ioc->internal_free_list)) {
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ printk(MPT2SAS_ERR_FMT "%s: smid not available\n",
+ ioc->name, __func__);
+ return 0;
+ }
+
+ request = list_entry(ioc->internal_free_list.next,
+ struct request_tracker, tracker_list);
+ request->cb_idx = cb_idx;
+ smid = request->smid;
+ list_del(&request->tracker_list);
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return smid;
+}
+
+/**
+ * mpt2sas_base_get_smid_scsiio - obtain a free smid from scsiio queue
+ * @ioc: per adapter object
+ * @cb_idx: callback index
+ * @scmd: pointer to scsi command object
+ *
+ * Returns smid (zero is invalid)
+ */
+u16
+mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx,
+ struct scsi_cmnd *scmd)
+{
+ unsigned long flags;
+ struct request_tracker *request;
+ u16 smid;
+
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
if (list_empty(&ioc->free_list)) {
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
printk(MPT2SAS_ERR_FMT "%s: smid not available\n",
@@ -1281,6 +1409,36 @@ mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)
request = list_entry(ioc->free_list.next,
struct request_tracker, tracker_list);
+ request->scmd = scmd;
+ request->cb_idx = cb_idx;
+ smid = request->smid;
+ list_del(&request->tracker_list);
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return smid;
+}
+
+/**
+ * mpt2sas_base_get_smid_hpr - obtain a free smid from hi-priority queue
+ * @ioc: per adapter object
+ * @cb_idx: callback index
+ *
+ * Returns smid (zero is invalid)
+ */
+u16
+mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx)
+{
+ unsigned long flags;
+ struct request_tracker *request;
+ u16 smid;
+
+ spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
+ if (list_empty(&ioc->hpr_free_list)) {
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return 0;
+ }
+
+ request = list_entry(ioc->hpr_free_list.next,
+ struct request_tracker, tracker_list);
request->cb_idx = cb_idx;
smid = request->smid;
list_del(&request->tracker_list);
@@ -1300,10 +1458,32 @@ void
mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
unsigned long flags;
+ int i;
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- ioc->scsi_lookup[smid - 1].cb_idx = 0xFF;
- list_add_tail(&ioc->scsi_lookup[smid - 1].tracker_list,
+ if (smid >= ioc->hi_priority_smid) {
+ if (smid < ioc->internal_smid) {
+ /* hi-priority */
+ i = smid - ioc->hi_priority_smid;
+ ioc->hpr_lookup[i].cb_idx = 0xFF;
+ list_add_tail(&ioc->hpr_lookup[i].tracker_list,
+ &ioc->hpr_free_list);
+ } else {
+ /* internal queue */
+ i = smid - ioc->internal_smid;
+ ioc->internal_lookup[i].cb_idx = 0xFF;
+ list_add_tail(&ioc->internal_lookup[i].tracker_list,
+ &ioc->internal_free_list);
+ }
+ spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return;
+ }
+
+ /* scsiio queue */
+ i = smid - 1;
+ ioc->scsi_lookup[i].cb_idx = 0xFF;
+ ioc->scsi_lookup[i].scmd = NULL;
+ list_add_tail(&ioc->scsi_lookup[i].tracker_list,
&ioc->free_list);
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
@@ -1352,21 +1532,19 @@ static inline void _base_writeq(__u64 b, volatile void __iomem *addr,
* mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware
* @ioc: per adapter object
* @smid: system request message index
- * @vf_id: virtual function id
* @handle: device handle
*
* Return nothing.
*/
void
-mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
- u16 handle)
+mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO;
- descriptor.SCSIIO.VF_ID = vf_id;
+ descriptor.SCSIIO.MSIxIndex = 0; /* TODO */
descriptor.SCSIIO.SMID = cpu_to_le16(smid);
descriptor.SCSIIO.DevHandle = cpu_to_le16(handle);
descriptor.SCSIIO.LMID = 0;
@@ -1379,20 +1557,18 @@ mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
* mpt2sas_base_put_smid_hi_priority - send Task Managment request to firmware
* @ioc: per adapter object
* @smid: system request message index
- * @vf_id: virtual function id
*
* Return nothing.
*/
void
-mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u8 vf_id)
+mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
descriptor.HighPriority.RequestFlags =
MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;
- descriptor.HighPriority.VF_ID = vf_id;
+ descriptor.HighPriority.MSIxIndex = 0; /* TODO */
descriptor.HighPriority.SMID = cpu_to_le16(smid);
descriptor.HighPriority.LMID = 0;
descriptor.HighPriority.Reserved1 = 0;
@@ -1404,18 +1580,17 @@ mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid,
* mpt2sas_base_put_smid_default - Default, primarily used for config pages
* @ioc: per adapter object
* @smid: system request message index
- * @vf_id: virtual function id
*
* Return nothing.
*/
void
-mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id)
+mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE;
- descriptor.Default.VF_ID = vf_id;
+ descriptor.Default.MSIxIndex = 0; /* TODO */
descriptor.Default.SMID = cpu_to_le16(smid);
descriptor.Default.LMID = 0;
descriptor.Default.DescriptorTypeDependent = 0;
@@ -1427,21 +1602,20 @@ mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id)
* mpt2sas_base_put_smid_target_assist - send Target Assist/Status to firmware
* @ioc: per adapter object
* @smid: system request message index
- * @vf_id: virtual function id
* @io_index: value used to track the IO
*
* Return nothing.
*/
void
mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u8 vf_id, u16 io_index)
+ u16 io_index)
{
Mpi2RequestDescriptorUnion_t descriptor;
u64 *request = (u64 *)&descriptor;
descriptor.SCSITarget.RequestFlags =
MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET;
- descriptor.SCSITarget.VF_ID = vf_id;
+ descriptor.SCSITarget.MSIxIndex = 0; /* TODO */
descriptor.SCSITarget.SMID = cpu_to_le16(smid);
descriptor.SCSITarget.LMID = 0;
descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index);
@@ -1594,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++;
@@ -1717,6 +1897,8 @@ _base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc)
}
kfree(ioc->scsi_lookup);
+ kfree(ioc->hpr_lookup);
+ kfree(ioc->internal_lookup);
}
@@ -1736,7 +1918,6 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
u16 num_of_reply_frames;
u16 chains_needed_per_io;
u32 sz, total_sz;
- u16 i;
u32 retry_sz;
u16 max_request_credit;
@@ -1764,7 +1945,10 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
MPT2SAS_MAX_REQUEST_QUEUE) ? MPT2SAS_MAX_REQUEST_QUEUE :
facts->RequestCredit;
}
- ioc->request_depth = max_request_credit;
+
+ ioc->hba_queue_depth = max_request_credit;
+ ioc->hi_priority_depth = facts->HighPriorityCredit;
+ ioc->internal_depth = ioc->hi_priority_depth + 5;
/* request frame size */
ioc->request_sz = facts->IOCRequestFrameSize * 4;
@@ -1802,7 +1986,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
ioc->chains_needed_per_io = chains_needed_per_io;
/* reply free queue sizing - taking into account for events */
- num_of_reply_frames = ioc->request_depth + 32;
+ num_of_reply_frames = ioc->hba_queue_depth + 32;
/* number of replies frames can't be a multiple of 16 */
/* decrease number of reply frames by 1 */
@@ -1823,7 +2007,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
* frames
*/
- queue_size = ioc->request_depth + num_of_reply_frames + 1;
+ queue_size = ioc->hba_queue_depth + num_of_reply_frames + 1;
/* round up to 16 byte boundary */
if (queue_size % 16)
queue_size += 16 - (queue_size % 16);
@@ -1837,60 +2021,85 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
if (queue_diff % 16)
queue_diff += 16 - (queue_diff % 16);
- /* adjust request_depth, reply_free_queue_depth,
+ /* adjust hba_queue_depth, reply_free_queue_depth,
* and queue_size
*/
- ioc->request_depth -= queue_diff;
+ ioc->hba_queue_depth -= queue_diff;
ioc->reply_free_queue_depth -= queue_diff;
queue_size -= queue_diff;
}
ioc->reply_post_queue_depth = queue_size;
- /* max scsi host queue depth */
- ioc->shost->can_queue = ioc->request_depth - INTERNAL_CMDS_COUNT;
- dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host queue: depth"
- "(%d)\n", ioc->name, ioc->shost->can_queue));
-
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: "
"sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), "
"chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message,
ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize,
ioc->chains_needed_per_io));
+ ioc->scsiio_depth = ioc->hba_queue_depth -
+ ioc->hi_priority_depth - ioc->internal_depth;
+
+ /* set the scsi host can_queue depth
+ * with some internal commands that could be outstanding
+ */
+ ioc->shost->can_queue = ioc->scsiio_depth - (2);
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: "
+ "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue));
+
/* contiguous pool for request and chains, 16 byte align, one extra "
* "frame for smid=0
*/
- ioc->chain_depth = ioc->chains_needed_per_io * ioc->request_depth;
- sz = ((ioc->request_depth + 1 + ioc->chain_depth) * ioc->request_sz);
+ ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth;
+ sz = ((ioc->scsiio_depth + 1 + ioc->chain_depth) * ioc->request_sz);
+
+ /* hi-priority queue */
+ sz += (ioc->hi_priority_depth * ioc->request_sz);
+
+ /* internal queue */
+ sz += (ioc->internal_depth * ioc->request_sz);
ioc->request_dma_sz = sz;
ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma);
if (!ioc->request) {
printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
- "failed: req_depth(%d), chains_per_io(%d), frame_sz(%d), "
- "total(%d kB)\n", ioc->name, ioc->request_depth,
+ "failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), "
+ "total(%d kB)\n", ioc->name, ioc->hba_queue_depth,
ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
- if (ioc->request_depth < MPT2SAS_SAS_QUEUE_DEPTH)
+ if (ioc->scsiio_depth < MPT2SAS_SAS_QUEUE_DEPTH)
goto out;
retry_sz += 64;
- ioc->request_depth = max_request_credit - retry_sz;
+ ioc->hba_queue_depth = max_request_credit - retry_sz;
goto retry_allocation;
}
if (retry_sz)
printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent "
- "succeed: req_depth(%d), chains_per_io(%d), frame_sz(%d), "
- "total(%d kb)\n", ioc->name, ioc->request_depth,
+ "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), "
+ "total(%d kb)\n", ioc->name, ioc->hba_queue_depth,
ioc->chains_needed_per_io, ioc->request_sz, sz/1024);
- ioc->chain = ioc->request + ((ioc->request_depth + 1) *
+
+ /* hi-priority queue */
+ ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) *
+ ioc->request_sz);
+ ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) *
+ ioc->request_sz);
+
+ /* internal queue */
+ ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth *
+ ioc->request_sz);
+ ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth *
+ ioc->request_sz);
+
+ ioc->chain = ioc->internal + (ioc->internal_depth *
ioc->request_sz);
- ioc->chain_dma = ioc->request_dma + ((ioc->request_depth + 1) *
+ ioc->chain_dma = ioc->internal_dma + (ioc->internal_depth *
ioc->request_sz);
+
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): "
"depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name,
- ioc->request, ioc->request_depth, ioc->request_sz,
- ((ioc->request_depth + 1) * ioc->request_sz)/1024));
+ ioc->request, ioc->hba_queue_depth, ioc->request_sz,
+ (ioc->hba_queue_depth * ioc->request_sz)/1024));
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool(0x%p): depth"
"(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->chain,
ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth *
@@ -1899,7 +2108,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
ioc->name, (unsigned long long) ioc->request_dma));
total_sz += sz;
- ioc->scsi_lookup = kcalloc(ioc->request_depth,
+ ioc->scsi_lookup = kcalloc(ioc->scsiio_depth,
sizeof(struct request_tracker), GFP_KERNEL);
if (!ioc->scsi_lookup) {
printk(MPT2SAS_ERR_FMT "scsi_lookup: kcalloc failed\n",
@@ -1907,12 +2116,38 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
goto out;
}
- /* initialize some bits */
- for (i = 0; i < ioc->request_depth; i++)
- ioc->scsi_lookup[i].smid = i + 1;
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsiio(0x%p): "
+ "depth(%d)\n", ioc->name, ioc->request,
+ ioc->scsiio_depth));
+
+ /* initialize hi-priority queue smid's */
+ ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth,
+ sizeof(struct request_tracker), GFP_KERNEL);
+ if (!ioc->hpr_lookup) {
+ printk(MPT2SAS_ERR_FMT "hpr_lookup: kcalloc failed\n",
+ ioc->name);
+ goto out;
+ }
+ ioc->hi_priority_smid = ioc->scsiio_depth + 1;
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hi_priority(0x%p): "
+ "depth(%d), start smid(%d)\n", ioc->name, ioc->hi_priority,
+ ioc->hi_priority_depth, ioc->hi_priority_smid));
+
+ /* initialize internal queue smid's */
+ ioc->internal_lookup = kcalloc(ioc->internal_depth,
+ sizeof(struct request_tracker), GFP_KERNEL);
+ if (!ioc->internal_lookup) {
+ printk(MPT2SAS_ERR_FMT "internal_lookup: kcalloc failed\n",
+ ioc->name);
+ goto out;
+ }
+ ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth;
+ dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "internal(0x%p): "
+ "depth(%d), start smid(%d)\n", ioc->name, ioc->internal,
+ ioc->internal_depth, ioc->internal_smid));
/* sense buffers, 4 byte align */
- sz = ioc->request_depth * SCSI_SENSE_BUFFERSIZE;
+ sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE;
ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4,
0);
if (!ioc->sense_dma_pool) {
@@ -1929,7 +2164,7 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
}
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT
"sense pool(0x%p): depth(%d), element_size(%d), pool_size"
- "(%d kB)\n", ioc->name, ioc->sense, ioc->request_depth,
+ "(%d kB)\n", ioc->name, ioc->sense, ioc->scsiio_depth,
SCSI_SENSE_BUFFERSIZE, sz/1024));
dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_dma(0x%llx)\n",
ioc->name, (unsigned long long)ioc->sense_dma));
@@ -2304,7 +2539,7 @@ _base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes,
((request_bytes/4)<<MPI2_DOORBELL_ADD_DWORDS_SHIFT)),
&ioc->chip->Doorbell);
- if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) {
+ if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) {
printk(MPT2SAS_ERR_FMT "doorbell handshake "
"int failed (line=%d)\n", ioc->name, __LINE__);
return -EFAULT;
@@ -2454,7 +2689,8 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET)
ioc->ioc_link_reset_in_progress = 1;
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->base_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
msecs_to_jiffies(10000));
if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET ||
@@ -2555,7 +2791,8 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
request = mpt2sas_base_get_msg_frame(ioc, smid);
ioc->base_cmds.smid = smid;
memcpy(request, mpi_request, sizeof(Mpi2SepReply_t));
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->base_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
msecs_to_jiffies(10000));
if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
@@ -2701,17 +2938,18 @@ _base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
/**
* _base_send_ioc_init - send ioc_init to firmware
* @ioc: per adapter object
- * @VF_ID: virtual function id
* @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+_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__));
@@ -2719,7 +2957,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t));
mpi_request.Function = MPI2_FUNCTION_IOC_INIT;
mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER;
- mpi_request.VF_ID = VF_ID;
+ mpi_request.VF_ID = 0; /* TODO */
+ mpi_request.VP_ID = 0;
mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION);
mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION);
@@ -2761,6 +3000,13 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, 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;
@@ -2783,7 +3029,8 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, 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;
@@ -2795,13 +3042,12 @@ _base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
/**
* _base_send_port_enable - send port_enable(discovery stuff) to firmware
* @ioc: per adapter object
- * @VF_ID: virtual function id
* @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
{
Mpi2PortEnableRequest_t *mpi_request;
u32 ioc_state;
@@ -2829,9 +3075,11 @@ _base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
ioc->base_cmds.smid = smid;
memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t));
mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE;
- mpi_request->VF_ID = VF_ID;
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
- mpt2sas_base_put_smid_default(ioc, smid, VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->base_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->base_cmds.done,
300*HZ);
if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
@@ -2892,13 +3140,12 @@ _base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event)
/**
* _base_event_notification - send event notification
* @ioc: per adapter object
- * @VF_ID: virtual function id
* @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
+_base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
{
Mpi2EventNotificationRequest_t *mpi_request;
unsigned long timeleft;
@@ -2926,11 +3173,13 @@ _base_event_notification(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, int sleep_flag)
ioc->base_cmds.smid = smid;
memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t));
mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION;
- mpi_request->VF_ID = VF_ID;
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
mpi_request->EventMasks[i] =
le32_to_cpu(ioc->event_masks[i]);
- mpt2sas_base_put_smid_default(ioc, smid, VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->base_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ);
if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) {
printk(MPT2SAS_ERR_FMT "%s: timeout\n",
@@ -2981,7 +3230,7 @@ mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type)
return;
mutex_lock(&ioc->base_cmds.mutex);
- _base_event_notification(ioc, 0, CAN_SLEEP);
+ _base_event_notification(ioc, CAN_SLEEP);
mutex_unlock(&ioc->base_cmds.mutex);
}
@@ -3006,7 +3255,6 @@ _base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
drsprintk(ioc, printk(MPT2SAS_DEBUG_FMT "clear interrupts\n",
ioc->name));
- writel(0, &ioc->chip->HostInterruptStatus);
count = 0;
do {
@@ -3160,30 +3408,60 @@ _base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
/**
* _base_make_ioc_operational - put controller in OPERATIONAL state
* @ioc: per adapter object
- * @VF_ID: virtual function id
* @sleep_flag: CAN_SLEEP or NO_SLEEP
*
* Returns 0 for success, non-zero for failure.
*/
static int
-_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- int sleep_flag)
+_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
{
int r, i;
unsigned long flags;
u32 reply_address;
+ u16 smid;
+ struct _tr_list *delayed_tr, *delayed_tr_next;
dinitprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s\n", ioc->name,
__func__));
+ /* clean the delayed target reset list */
+ list_for_each_entry_safe(delayed_tr, delayed_tr_next,
+ &ioc->delayed_tr_list, list) {
+ list_del(&delayed_tr->list);
+ kfree(delayed_tr);
+ }
+
/* initialize the scsi lookup free list */
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
INIT_LIST_HEAD(&ioc->free_list);
- for (i = 0; i < ioc->request_depth; i++) {
+ smid = 1;
+ for (i = 0; i < ioc->scsiio_depth; i++, smid++) {
ioc->scsi_lookup[i].cb_idx = 0xFF;
+ ioc->scsi_lookup[i].smid = smid;
+ ioc->scsi_lookup[i].scmd = NULL;
list_add_tail(&ioc->scsi_lookup[i].tracker_list,
&ioc->free_list);
}
+
+ /* hi-priority queue */
+ INIT_LIST_HEAD(&ioc->hpr_free_list);
+ smid = ioc->hi_priority_smid;
+ for (i = 0; i < ioc->hi_priority_depth; i++, smid++) {
+ ioc->hpr_lookup[i].cb_idx = 0xFF;
+ ioc->hpr_lookup[i].smid = smid;
+ list_add_tail(&ioc->hpr_lookup[i].tracker_list,
+ &ioc->hpr_free_list);
+ }
+
+ /* internal queue */
+ INIT_LIST_HEAD(&ioc->internal_free_list);
+ smid = ioc->internal_smid;
+ for (i = 0; i < ioc->internal_depth; i++, smid++) {
+ ioc->internal_lookup[i].cb_idx = 0xFF;
+ ioc->internal_lookup[i].smid = smid;
+ list_add_tail(&ioc->internal_lookup[i].tracker_list,
+ &ioc->internal_free_list);
+ }
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
/* initialize Reply Free Queue */
@@ -3196,7 +3474,7 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
for (i = 0; i < ioc->reply_post_queue_depth; i++)
ioc->reply_post_free[i].Words = ULLONG_MAX;
- r = _base_send_ioc_init(ioc, VF_ID, sleep_flag);
+ r = _base_send_ioc_init(ioc, sleep_flag);
if (r)
return r;
@@ -3207,14 +3485,14 @@ _base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
writel(0, &ioc->chip->ReplyPostHostIndex);
_base_unmask_interrupts(ioc);
- r = _base_event_notification(ioc, VF_ID, sleep_flag);
+ r = _base_event_notification(ioc, sleep_flag);
if (r)
return r;
if (sleep_flag == CAN_SLEEP)
_base_static_config_pages(ioc);
- r = _base_send_port_enable(ioc, VF_ID, sleep_flag);
+ r = _base_send_port_enable(ioc, sleep_flag);
if (r)
return r;
@@ -3270,14 +3548,25 @@ 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;
+ ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
+ sizeof(Mpi2PortFactsReply_t), GFP_KERNEL);
+ if (!ioc->pfacts)
+ goto out_free_resources;
+
+ for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
+ r = _base_get_port_facts(ioc, i, CAN_SLEEP);
+ if (r)
+ goto out_free_resources;
+ }
+
r = _base_allocate_memory_pools(ioc, CAN_SLEEP);
if (r)
goto out_free_resources;
@@ -3286,7 +3575,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
/* base internal command bits */
mutex_init(&ioc->base_cmds.mutex);
- init_completion(&ioc->base_cmds.done);
ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
ioc->base_cmds.status = MPT2_CMD_NOT_USED;
@@ -3294,7 +3582,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
ioc->transport_cmds.status = MPT2_CMD_NOT_USED;
mutex_init(&ioc->transport_cmds.mutex);
- init_completion(&ioc->transport_cmds.done);
/* task management internal command bits */
ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
@@ -3310,7 +3597,6 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL);
ioc->ctl_cmds.status = MPT2_CMD_NOT_USED;
mutex_init(&ioc->ctl_cmds.mutex);
- init_completion(&ioc->ctl_cmds.done);
for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++)
ioc->event_masks[i] = -1;
@@ -3327,22 +3613,13 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
_base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS);
_base_unmask_events(ioc, MPI2_EVENT_TASK_SET_FULL);
_base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED);
-
- ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts,
- sizeof(Mpi2PortFactsReply_t), GFP_KERNEL);
- if (!ioc->pfacts)
- goto out_free_resources;
-
- for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) {
- r = _base_get_port_facts(ioc, i, CAN_SLEEP);
- if (r)
- goto out_free_resources;
- }
- r = _base_make_ioc_operational(ioc, 0, CAN_SLEEP);
+ r = _base_make_ioc_operational(ioc, CAN_SLEEP);
if (r)
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:
@@ -3466,7 +3743,7 @@ _wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
/* pending command count */
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- for (i = 0; i < ioc->request_depth; i++)
+ for (i = 0; i < ioc->scsiio_depth; i++)
if (ioc->scsi_lookup[i].cb_idx != 0xFF)
ioc->pending_io_count++;
spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
@@ -3490,12 +3767,15 @@ int
mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
enum reset_type type)
{
- int r, i;
+ int r;
unsigned long flags;
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);
@@ -3513,9 +3793,7 @@ mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag,
if (r)
goto out;
_base_reset_handler(ioc, MPT2_IOC_AFTER_RESET);
- for (i = 0 ; i < ioc->facts.NumberOfPorts; i++)
- r = _base_make_ioc_operational(ioc, ioc->pfacts[i].VF_ID,
- sleep_flag);
+ r = _base_make_ioc_operational(ioc, sleep_flag);
if (!r)
_base_reset_handler(ioc, MPT2_IOC_DONE_RESET);
out:
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 2faab1e690e9..bb4f14656afa 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -3,7 +3,7 @@
* for access to MPT (Message Passing Technology) firmware.
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.h
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -69,10 +69,10 @@
#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 "01.100.06.00"
-#define MPT2SAS_MAJOR_VERSION 01
+#define MPT2SAS_DRIVER_VERSION "03.100.03.00"
+#define MPT2SAS_MAJOR_VERSION 03
#define MPT2SAS_MINOR_VERSION 100
-#define MPT2SAS_BUILD_VERSION 06
+#define MPT2SAS_BUILD_VERSION 03
#define MPT2SAS_RELEASE_VERSION 00
/*
@@ -264,6 +264,13 @@ struct _internal_cmd {
* SAS Topology Structures
*/
+#define MPTSAS_STATE_TR_SEND 0x0001
+#define MPTSAS_STATE_TR_COMPLETE 0x0002
+#define MPTSAS_STATE_CNTRL_SEND 0x0004
+#define MPTSAS_STATE_CNTRL_COMPLETE 0x0008
+
+#define MPT2SAS_REQ_SAS_CNTRL 0x0010
+
/**
* struct _sas_device - attached device information
* @list: sas device list
@@ -271,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)
@@ -289,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;
@@ -300,6 +307,7 @@ struct _sas_device {
u16 slot;
u8 hidden_raid_component;
u8 responding;
+ u16 state;
};
/**
@@ -344,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
@@ -354,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;
@@ -390,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
@@ -403,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;
@@ -436,6 +440,17 @@ struct request_tracker {
struct list_head tracker_list;
};
+/**
+ * struct _tr_list - target reset list
+ * @handle: device handle
+ * @state: state machine
+ */
+struct _tr_list {
+ struct list_head list;
+ u16 handle;
+ u16 state;
+};
+
typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
/**
@@ -451,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
@@ -476,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:
@@ -510,8 +528,9 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @config_page_sz: config page size
* @config_page: reserve memory for config page payload
* @config_page_dma:
+ * @hba_queue_depth: hba request queue depth
* @sge_size: sg element size for either 32/64 bit
- * @request_depth: hba request queue depth
+ * @scsiio_depth: SCSI_IO queue depth
* @request_sz: per request frame size
* @request: pool of request frames
* @request_dma:
@@ -528,6 +547,18 @@ typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr);
* @chains_needed_per_io: max chains per io
* @chain_offset_value_for_main_message: location 1st sg in main
* @chain_depth: total chains allocated
+ * @hi_priority_smid:
+ * @hi_priority:
+ * @hi_priority_dma:
+ * @hi_priority_depth:
+ * @hpr_lookup:
+ * @hpr_free_list:
+ * @internal_smid:
+ * @internal:
+ * @internal_dma:
+ * @internal_depth:
+ * @internal_lookup:
+ * @internal_free_list:
* @sense: pool of sense
* @sense_dma:
* @sense_dma_pool:
@@ -559,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;
@@ -594,11 +626,15 @@ 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;
+ u8 tm_tr_cb_idx;
+ 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;
@@ -643,9 +679,10 @@ struct MPT2SAS_ADAPTER {
void *config_page;
dma_addr_t config_page_dma;
- /* request */
+ /* scsiio request */
+ u16 hba_queue_depth;
u16 sge_size;
- u16 request_depth;
+ u16 scsiio_depth;
u16 request_sz;
u8 *request;
dma_addr_t request_dma;
@@ -665,6 +702,22 @@ struct MPT2SAS_ADAPTER {
u16 chain_offset_value_for_main_message;
u16 chain_depth;
+ /* hi-priority queue */
+ u16 hi_priority_smid;
+ u8 *hi_priority;
+ dma_addr_t hi_priority_dma;
+ u16 hi_priority_depth;
+ struct request_tracker *hpr_lookup;
+ struct list_head hpr_free_list;
+
+ /* internal queue */
+ u16 internal_smid;
+ u8 *internal;
+ dma_addr_t internal_dma;
+ u16 internal_depth;
+ struct request_tracker *internal_lookup;
+ struct list_head internal_free_list;
+
/* sense */
u8 *sense;
dma_addr_t sense_dma;
@@ -690,6 +743,8 @@ struct MPT2SAS_ADAPTER {
struct dma_pool *reply_post_free_dma_pool;
u32 reply_post_host_index;
+ struct list_head delayed_tr_list;
+
/* diag buffer support */
u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
u32 diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT];
@@ -701,7 +756,7 @@ struct MPT2SAS_ADAPTER {
u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT];
};
-typedef void (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
u32 reply);
@@ -720,22 +775,28 @@ 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_msg_frame_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid);
-dma_addr_t mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid);
+__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc,
+ u16 smid);
+
+/* hi-priority queue */
+u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx);
+u16 mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx,
+ struct scsi_cmnd *scmd);
u16 mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx);
void mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid);
-void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id,
+void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid,
u16 handle);
-void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id);
+void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- u8 vf_id, u16 io_index);
-void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 vf_id);
+ u16 io_index);
+void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid);
void mpt2sas_base_initialize_callback_handler(void);
u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func);
void mpt2sas_base_release_callback_handler(u8 cb_idx);
-void mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+u8 mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply);
void *mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr);
u32 mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked);
@@ -748,7 +809,11 @@ 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);
void mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
u8 type, u16 smid_task, ulong timeout);
void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle);
@@ -760,11 +825,11 @@ struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAP
struct _sas_device *mpt2sas_scsih_sas_device_find_by_sas_address(
struct MPT2SAS_ADAPTER *ioc, u64 sas_address);
-void mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply);
void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
/* config shared API */
-void mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+u8 mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply);
int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys);
int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page);
@@ -817,27 +882,35 @@ extern struct device_attribute *mpt2sas_host_attrs[];
extern struct device_attribute *mpt2sas_dev_attrs[];
void mpt2sas_ctl_init(void);
void mpt2sas_ctl_exit(void);
-void mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+u8 mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply);
void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase);
-void mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply);
+u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
+ u32 reply);
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 */
-void mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply);
+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);
+extern u8 mpt2sas_stm_zero_smid_handler(struct MPT2SAS_ADAPTER *ioc,
+ u8 msix_index, u32 reply);
extern int scsi_internal_device_unblock(struct scsi_device *sdev);
#endif /* MPT2SAS_BASE_H_INCLUDED */
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
index ab8c560865d8..594a389c6526 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_config.c
@@ -2,7 +2,7 @@
* This module provides common API for accessing firmware configuration pages
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -227,23 +227,25 @@ _config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc,
* mpt2sas_config_done - config page completion routine
* @ioc: per adapter object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
* Context: none.
*
* The callback handler when using _config_request.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+u8
+mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
if (ioc->config_cmds.status == MPT2_CMD_NOT_USED)
- return;
+ return 1;
if (ioc->config_cmds.smid != smid)
- return;
+ return 1;
ioc->config_cmds.status |= MPT2_CMD_COMPLETE;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (mpi_reply) {
@@ -257,6 +259,7 @@ mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
#endif
ioc->config_cmds.smid = USHORT_MAX;
complete(&ioc->config_cmds.done);
+ return 1;
}
/**
@@ -303,6 +306,9 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
retry_count = 0;
memset(&mem, 0, sizeof(struct config_request));
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
+
if (config_page) {
mpi_request->Header.PageVersion = mpi_reply->Header.PageVersion;
mpi_request->Header.PageNumber = mpi_reply->Header.PageNumber;
@@ -380,7 +386,7 @@ _config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t
_config_display_some_debug(ioc, smid, "config_request", NULL);
#endif
init_completion(&ioc->config_cmds.done);
- mpt2sas_base_put_smid_default(ioc, smid, config_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
timeleft = wait_for_completion_timeout(&ioc->config_cmds.done,
timeout*HZ);
if (!(ioc->config_cmds.status & MPT2_CMD_COMPLETE)) {
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index c2a51018910f..84a124f8e21f 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -3,7 +3,7 @@
* controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -219,23 +219,25 @@ _ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid,
* mpt2sas_ctl_done - ctl module completion routine
* @ioc: per adapter object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
* Context: none.
*
* The callback handler when using ioc->ctl_cb_idx.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+u8
+mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED)
- return;
+ return 1;
if (ioc->ctl_cmds.smid != smid)
- return;
+ return 1;
ioc->ctl_cmds.status |= MPT2_CMD_COMPLETE;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (mpi_reply) {
@@ -247,6 +249,7 @@ mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
#endif
ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING;
complete(&ioc->ctl_cmds.done);
+ return 1;
}
/**
@@ -328,22 +331,25 @@ mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc,
/**
* mpt2sas_ctl_event_callback - firmware event handler (called at ISR time)
* @ioc: per adapter object
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
* Context: interrupt.
*
* This function merely adds a new work task into ioc->firmware_event_thread.
* The tasks are worked from _firmware_event_work in user context.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
+u8
+mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
+ u32 reply)
{
Mpi2EventNotificationReply_t *mpi_reply;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
mpt2sas_ctl_add_to_event_log(ioc, mpi_reply);
+ return 1;
}
/**
@@ -507,7 +513,7 @@ _ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg,
handle = le16_to_cpu(tm_request->DevHandle);
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- for (i = ioc->request_depth; i && !found; i--) {
+ for (i = ioc->scsiio_depth; i && !found; i--) {
scmd = ioc->scsi_lookup[i - 1].scmd;
if (scmd == NULL || scmd->device == NULL ||
scmd->device->hostdata == NULL)
@@ -614,7 +620,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n",
ioc->name, __func__);
- smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx);
+ smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
@@ -734,10 +740,10 @@ _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, 0,
+ mpt2sas_base_put_smid_scsi_io(ioc, smid,
le16_to_cpu(mpi_request->FunctionDependent1));
break;
}
@@ -759,8 +765,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
mutex_lock(&ioc->tm_cmds.mutex);
mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu(
tm_request->DevHandle));
- mpt2sas_base_put_smid_hi_priority(ioc, smid,
- mpi_request->VF_ID);
+ mpt2sas_base_put_smid_hi_priority(ioc, smid);
break;
}
case MPI2_FUNCTION_SMP_PASSTHROUGH:
@@ -781,7 +786,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
ioc->ioc_link_reset_in_progress = 1;
ioc->ignore_loginfos = 1;
}
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
break;
}
case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL:
@@ -795,11 +800,11 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
ioc->ioc_link_reset_in_progress = 1;
ioc->ignore_loginfos = 1;
}
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
break;
}
default:
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
break;
}
@@ -807,6 +812,7 @@ _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc,
timeout = MPT2_IOCTL_DEFAULT_TIMEOUT;
else
timeout = karg.timeout;
+ init_completion(&ioc->ctl_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
timeout*HZ);
if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) {
@@ -842,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 */
@@ -890,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,
@@ -1223,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
*/
@@ -1243,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;
@@ -1273,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);
@@ -1299,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",
@@ -1332,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];
@@ -1367,10 +1363,12 @@ _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 */
+ mpi_request->VP_ID = 0;
dctlprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: diag_buffer(0x%p), "
"dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data,
@@ -1380,7 +1378,8 @@ _ctl_diag_register(void __user *arg, enum block_state state)
mpi_request->ProductSpecific[i] =
cpu_to_le32(ioc->product_specific[buffer_type][i]);
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->ctl_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -1413,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;
}
@@ -1429,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;
}
@@ -1591,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.
*
*/
@@ -1643,8 +1719,11 @@ _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset)
mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE;
mpi_request->BufferType = buffer_type;
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->ctl_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -1678,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;
}
@@ -1902,8 +1981,11 @@ _ctl_diag_read_buffer(void __user *arg, enum block_state state)
for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++)
mpi_request->ProductSpecific[i] =
cpu_to_le32(ioc->product_specific[buffer_type][i]);
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
- mpt2sas_base_put_smid_default(ioc, smid, mpi_request->VF_ID);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->ctl_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done,
MPT2_IOCTL_DEFAULT_TIMEOUT*HZ);
@@ -1936,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;
}
@@ -2069,6 +2151,7 @@ static long
_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret;
+
lock_kernel();
ret = _ctl_ioctl_main(file, cmd, (void __user *)arg);
unlock_kernel();
@@ -2143,6 +2226,7 @@ static long
_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg)
{
long ret;
+
lock_kernel();
if (cmd == MPT2COMMAND32)
ret = _ctl_compat_mpt_command(file, cmd, arg);
@@ -2457,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,
@@ -2470,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 4da11435533f..8a5eeb1a5c84 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
@@ -3,7 +3,7 @@
* controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -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_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h
index ad325096e842..5308a25cb307 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_debug.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h
@@ -2,7 +2,7 @@
* Logging Support for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 774b34525bba..8dc682f00fd2 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -2,7 +2,7 @@
* Scsi Host Layer for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -76,9 +76,13 @@ 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;
+static u8 tm_tr_cb_idx = -1 ;
+static u8 tm_sas_control_cb_idx = -1;
+
/* command line options */
static u32 logging_level;
MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info "
@@ -109,6 +113,7 @@ struct sense_info {
* @work: work object (ioc->fault_reset_work_q)
* @ioc: per adapter object
* @VF_ID: virtual function id
+ * @VP_ID: virtual port id
* @host_reset_handling: handling events during host reset
* @ignore: flag meaning this event has been marked to ignore
* @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h
@@ -121,6 +126,7 @@ struct fw_event_work {
struct work_struct work;
struct MPT2SAS_ADAPTER *ioc;
u8 VF_ID;
+ u8 VP_ID;
u8 host_reset_handling;
u8 ignore;
u16 event;
@@ -138,8 +144,10 @@ struct fw_event_work {
* @lun: lun number
* @cdb_length: cdb length
* @cdb: cdb contents
- * @valid_reply: flag set for reply message
* @timeout: timeout for this command
+ * @VF_ID: virtual function id
+ * @VP_ID: virtual port id
+ * @valid_reply: flag set for reply message
* @sense_length: sense length
* @ioc_status: ioc status
* @scsi_state: scsi state
@@ -161,6 +169,8 @@ struct _scsi_io_transfer {
u8 cdb_length;
u8 cdb[32];
u8 timeout;
+ u8 VF_ID;
+ u8 VP_ID;
u8 valid_reply;
/* the following bits are only valid when 'valid_reply = 1' */
u32 sense_length;
@@ -187,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);
@@ -308,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
@@ -501,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__,
@@ -512,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);
}
@@ -544,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
@@ -690,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
@@ -756,66 +821,16 @@ _scsih_is_end_device(u32 device_info)
}
/**
- * _scsih_scsi_lookup_get - returns scmd entry
+ * mptscsih_get_scsi_lookup - returns scmd entry
* @ioc: per adapter object
* @smid: system request message index
- * Context: This function will acquire ioc->scsi_lookup_lock.
*
* Returns the smid stored scmd pointer.
*/
static struct scsi_cmnd *
_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid)
{
- unsigned long flags;
- struct scsi_cmnd *scmd;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- scmd = ioc->scsi_lookup[smid - 1].scmd;
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return scmd;
-}
-
-/**
- * mptscsih_getclear_scsi_lookup - returns scmd entry
- * @ioc: per adapter object
- * @smid: system request message index
- * Context: This function will acquire ioc->scsi_lookup_lock.
- *
- * Returns the smid stored scmd pointer, as well as clearing the scmd pointer.
- */
-static struct scsi_cmnd *
-_scsih_scsi_lookup_getclear(struct MPT2SAS_ADAPTER *ioc, u16 smid)
-{
- unsigned long flags;
- struct scsi_cmnd *scmd;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- scmd = ioc->scsi_lookup[smid - 1].scmd;
- ioc->scsi_lookup[smid - 1].scmd = NULL;
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
- return scmd;
-}
-
-/**
- * _scsih_scsi_lookup_set - updates scmd entry in lookup
- * @ioc: per adapter object
- * @smid: system request message index
- * @scmd: pointer to scsi command object
- * Context: This function will acquire ioc->scsi_lookup_lock.
- *
- * This will save scmd pointer in the scsi_lookup array.
- *
- * Return nothing.
- */
-static void
-_scsih_scsi_lookup_set(struct MPT2SAS_ADAPTER *ioc, u16 smid,
- struct scsi_cmnd *scmd)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
- ioc->scsi_lookup[smid - 1].scmd = scmd;
- spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags);
+ return ioc->scsi_lookup[smid - 1].scmd;
}
/**
@@ -838,9 +853,9 @@ _scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
smid = 0;
- for (i = 0; i < ioc->request_depth; i++) {
+ for (i = 0; i < ioc->scsiio_depth; i++) {
if (ioc->scsi_lookup[i].scmd == scmd) {
- smid = i + 1;
+ smid = ioc->scsi_lookup[i].smid;
goto out;
}
}
@@ -869,7 +884,7 @@ _scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id,
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
found = 0;
- for (i = 0 ; i < ioc->request_depth; i++) {
+ for (i = 0 ; i < ioc->scsiio_depth; i++) {
if (ioc->scsi_lookup[i].scmd &&
(ioc->scsi_lookup[i].scmd->device->id == id &&
ioc->scsi_lookup[i].scmd->device->channel == channel)) {
@@ -903,7 +918,7 @@ _scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id,
spin_lock_irqsave(&ioc->scsi_lookup_lock, flags);
found = 0;
- for (i = 0 ; i < ioc->request_depth; i++) {
+ for (i = 0 ; i < ioc->scsiio_depth; i++) {
if (ioc->scsi_lookup[i].scmd &&
(ioc->scsi_lookup[i].scmd->device->id == id &&
ioc->scsi_lookup[i].scmd->device->channel == channel &&
@@ -1093,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)
@@ -1113,7 +1153,7 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
}
/**
- * _scsih_change_queue_depth - changing device queue tag type
+ * _scsih_change_queue_type - changing device queue tag type
* @sdev: scsi device struct
* @tag_type: requested tag type
*
@@ -1679,23 +1719,24 @@ _scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code)
* _scsih_tm_done - tm completion routine
* @ioc: per adapter object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
* Context: none.
*
* The callback handler when using scsih_issue_tm.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-static void
-_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+static u8
+_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
{
MPI2DefaultReply_t *mpi_reply;
if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED)
- return;
+ return 1;
if (ioc->tm_cmds.smid != smid)
- return;
+ return 1;
ioc->tm_cmds.status |= MPT2_CMD_COMPLETE;
mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
if (mpi_reply) {
@@ -1704,6 +1745,7 @@ _scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
}
ioc->tm_cmds.status &= ~MPT2_CMD_PENDING;
complete(&ioc->tm_cmds.done);
+ return 1;
}
/**
@@ -1790,7 +1832,6 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
u16 smid = 0;
u32 ioc_state;
unsigned long timeleft;
- u8 VF_ID = 0;
if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) {
printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n",
@@ -1817,7 +1858,7 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
goto issue_host_reset;
}
- smid = mpt2sas_base_get_smid(ioc, ioc->tm_cb_idx);
+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
@@ -1825,7 +1866,8 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
}
dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x),"
- " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, smid));
+ " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type,
+ smid_task));
ioc->tm_cmds.status = MPT2_CMD_PENDING;
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
ioc->tm_cmds.smid = smid;
@@ -1834,10 +1876,12 @@ mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint lun,
mpi_request->DevHandle = cpu_to_le16(handle);
mpi_request->TaskType = type;
mpi_request->TaskMID = cpu_to_le16(smid_task);
+ mpi_request->VP_ID = 0; /* TODO */
+ mpi_request->VF_ID = 0;
int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN);
mpt2sas_scsih_set_tm_flag(ioc, handle);
init_completion(&ioc->tm_cmds.done);
- mpt2sas_base_put_smid_hi_priority(ioc, smid, VF_ID);
+ mpt2sas_base_put_smid_hi_priority(ioc, smid);
timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ);
mpt2sas_scsih_clear_tm_flag(ioc, handle);
if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) {
@@ -1911,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,
@@ -2075,7 +2121,7 @@ _scsih_target_reset(struct scsi_cmnd *scmd)
}
/**
- * _scsih_abort - eh threads main host reset routine
+ * _scsih_host_reset - eh threads main host reset routine
* @sdev: scsi device struct
*
* Returns SUCCESS if command aborted else FAILED
@@ -2334,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);
@@ -2345,12 +2390,247 @@ _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);
+ }
+}
+
+/**
+ * _scsih_tm_tr_send - send task management request
+ * @ioc: per adapter object
+ * @handle: device handle
+ * Context: interrupt time.
+ *
+ * This code is to initiate the device removal handshake protocal
+ * with controller firmware. This function will issue target reset
+ * using high priority request queue. It will send a sas iounit
+ * controll request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion.
+ *
+ * This is designed to send muliple task management request at the same
+ * time to the fifo. If the fifo is full, we will append the request,
+ * and process it in a future completion.
+ */
+static void
+_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle)
+{
+ Mpi2SCSITaskManagementRequest_t *mpi_request;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
+ u16 smid;
+ struct _sas_device *sas_device;
+ unsigned long flags;
+ struct _tr_list *delayed_tr;
+
+ if (ioc->shost_recovery) {
+ printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+ __func__, ioc->name);
+ return;
+ }
+
+ spin_lock_irqsave(&ioc->sas_device_lock, flags);
+ sas_device = _scsih_sas_device_find_by_handle(ioc, handle);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ /* skip is hidden raid component */
+ if (sas_device && sas_device->hidden_raid_component)
+ return;
+
+ smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx);
+ if (!smid) {
+ delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC);
+ if (!delayed_tr)
+ return;
+ INIT_LIST_HEAD(&delayed_tr->list);
+ delayed_tr->handle = handle;
+ delayed_tr->state = MPT2SAS_REQ_SAS_CNTRL;
+ list_add_tail(&delayed_tr->list,
+ &ioc->delayed_tr_list);
+ if (sas_device && sas_device->starget) {
+ dewtprintk(ioc, starget_printk(KERN_INFO,
+ sas_device->starget, "DELAYED:tr:handle(0x%04x), "
+ "(open)\n", handle));
+ } else {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT
+ "DELAYED:tr:handle(0x%04x), (open)\n",
+ ioc->name, handle));
+ }
+ return;
+ }
+
+ 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);
+ memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t));
+ mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT;
+ mpi_request->DevHandle = cpu_to_le16(handle);
+ mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
+ mpt2sas_base_put_smid_hi_priority(ioc, smid);
+}
+
+
+
+/**
+ * _scsih_sas_control_complete - completion routine
+ * @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)
+ * Context: interrupt time.
+ *
+ * This is the sas iounit controll completion routine.
+ * This code is part of the code to initiate the device removal
+ * handshake protocal with controller firmware.
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
+ */
+static u8
+_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid,
+ u8 msix_index, u32 reply)
+{
+ unsigned long flags;
+ u16 handle;
+ struct _sas_device *sas_device;
+ Mpi2SasIoUnitControlReply_t *mpi_reply =
+ mpt2sas_base_get_reply_virt_addr(ioc, reply);
+
+ 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);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ 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",
+ ioc->name, handle, le16_to_cpu(mpi_reply->IOCStatus),
+ le32_to_cpu(mpi_reply->IOCLogInfo)));
+ }
+
+ return 1;
+}
+
+/**
+ * _scsih_tm_tr_complete -
+ * @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)
+ * Context: interrupt time.
+ *
+ * This is the target reset completion routine.
+ * This code is part of the code to initiate the device removal
+ * handshake protocal with controller firmware.
+ * It will send a sas iounit controll request (MPI2_SAS_OP_REMOVE_DEVICE)
+ *
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
+ */
+static u8
+_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index,
+ u32 reply)
+{
+ unsigned long flags;
+ u16 handle;
+ struct _sas_device *sas_device;
+ Mpi2SCSITaskManagementReply_t *mpi_reply =
+ mpt2sas_base_get_reply_virt_addr(ioc, reply);
+ Mpi2SasIoUnitControlRequest_t *mpi_request;
+ u16 smid_sas_ctrl;
+ struct MPT2SAS_TARGET *sas_target_priv_data;
+ struct _tr_list *delayed_tr;
+ u8 rc;
+
+ 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);
+ spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
+
+ 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 (!list_empty(&ioc->delayed_tr_list)) {
+ delayed_tr = list_entry(ioc->delayed_tr_list.next,
+ struct _tr_list, list);
+ mpt2sas_base_free_smid(ioc, smid);
+ if (delayed_tr->state & MPT2SAS_REQ_SAS_CNTRL)
+ _scsih_tm_tr_send(ioc, delayed_tr->handle);
+ list_del(&delayed_tr->list);
+ kfree(delayed_tr);
+ rc = 0; /* tells base_interrupt not to free mf */
+ } else
+ rc = 1;
+
+ if (sas_device && !(sas_device->state & MPT2SAS_REQ_SAS_CNTRL))
+ return rc;
+
+ if (ioc->shost_recovery) {
+ printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n",
+ __func__, ioc->name);
+ return rc;
}
+
+ smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx);
+ if (!smid_sas_ctrl) {
+ printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
+ ioc->name, __func__);
+ 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;
+ mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl);
+ return rc;
}
/**
@@ -2375,6 +2655,21 @@ _scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc,
u16 expander_handle;
struct _sas_node *sas_expander;
unsigned long flags;
+ int i, reason_code;
+ u16 handle;
+
+ for (i = 0 ; i < event_data->NumEntries; i++) {
+ if (event_data->PHY[i].PhyStatus &
+ MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
+ continue;
+ handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
+ if (!handle)
+ continue;
+ reason_code = event_data->PHY[i].PhyStatus &
+ MPI2_EVENT_SAS_TOPO_RC_MASK;
+ if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)
+ _scsih_tm_tr_send(ioc, handle);
+ }
expander_handle = le16_to_cpu(event_data->ExpanderDevHandle);
if (expander_handle < ioc->sas_hba.num_phys) {
@@ -2433,8 +2728,8 @@ _scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc)
u16 smid;
u16 count = 0;
- for (smid = 1; smid <= ioc->request_depth; smid++) {
- scmd = _scsih_scsi_lookup_getclear(ioc, smid);
+ for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
+ scmd = _scsih_scsi_lookup_get(ioc, smid);
if (!scmd)
continue;
count++;
@@ -2475,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:
@@ -2484,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 =
@@ -2498,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);
}
/**
@@ -2585,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;
@@ -2616,7 +2908,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON))
mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON;
- smid = mpt2sas_base_get_smid(ioc, ioc->scsi_io_cb_idx);
+ smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd);
if (!smid) {
printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n",
ioc->name, __func__);
@@ -2639,11 +2931,12 @@ _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);
-
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *)
mpi_request->LUN);
memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len);
@@ -2657,8 +2950,7 @@ _scsih_qcmd(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *))
}
}
- _scsih_scsi_lookup_set(ioc, smid, scmd);
- mpt2sas_base_put_smid_scsi_io(ioc, smid, 0,
+ mpt2sas_base_put_smid_scsi_io(ioc, smid,
sas_device_priv_data->sas_target->handle);
return 0;
@@ -2856,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
@@ -2954,15 +3246,16 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle)
* _scsih_io_done - scsi request callback
* @ioc: per adapter object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
- * Callback handler when using scsih_qcmd.
+ * Callback handler when using _scsih_qcmd.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-static void
-_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
+static u8
+_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
{
Mpi2SCSIIORequest_t *mpi_request;
Mpi2SCSIIOReply_t *mpi_reply;
@@ -2973,12 +3266,12 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, 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_getclear(ioc, smid);
+ scmd = _scsih_scsi_lookup_get(ioc, smid);
if (scmd == NULL)
- return;
+ return 1;
mpi_request = mpt2sas_base_get_msg_frame(ioc, smid);
@@ -2995,16 +3288,16 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, 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);
@@ -3015,7 +3308,6 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, 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 &&
@@ -3051,10 +3343,9 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, 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;
@@ -3100,8 +3391,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, 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;
@@ -3134,12 +3427,12 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, u32 reply)
out:
scsi_dma_unmap(scmd);
scmd->scsi_done(scmd);
+ return 1;
}
/**
* _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
@@ -3149,13 +3442,14 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID, 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",
@@ -3169,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);
}
@@ -3302,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);
@@ -3357,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;
@@ -3386,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);
@@ -3398,9 +3697,8 @@ _scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle)
}
}
- sas_address = le64_to_cpu(expander_pg0.SASAddress);
-
spin_lock_irqsave(&ioc->sas_node_lock, flags);
+ sas_address = le64_to_cpu(expander_pg0.SASAddress);
sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc,
sas_address);
spin_unlock_irqrestore(&ioc->sas_node_lock, flags);
@@ -3418,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)
@@ -3441,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__);
@@ -3487,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;
@@ -3509,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);
}
@@ -3601,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 =
@@ -3632,40 +3966,42 @@ _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));
+ goto skip_tr;
+ }
+
/* Target Reset to flush out all the outstanding IO */
device_handle = (sas_device->hidden_raid_component) ?
sas_device->volume_handle : handle;
@@ -3682,6 +4018,13 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
if (ioc->shost_recovery)
goto out;
}
+ skip_tr:
+
+ if ((sas_device->state & MPTSAS_STATE_CNTRL_COMPLETE)) {
+ dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "\tskip "
+ "sas_cntrl handle(0x%04x)\n", ioc->name, handle));
+ goto out;
+ }
/* SAS_IO_UNIT_CNTR - send REMOVE_DEVICE */
dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sas_iounit: handle"
@@ -3690,7 +4033,8 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, u16 handle)
mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL;
mpi_request.Operation = MPI2_SAS_OP_REMOVE_DEVICE;
mpi_request.DevHandle = handle;
- mpi_request.VF_ID = 0;
+ mpi_request.VF_ID = 0; /* TODO */
+ mpi_request.VP_ID = 0;
if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply,
&mpi_request)) != 0) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
@@ -3707,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);
@@ -3734,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:
@@ -3744,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:
@@ -3769,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
@@ -3800,15 +4145,12 @@ _scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_topology_change_event - handle topology changes
* @ioc: per adapter object
- * @VF_ID:
- * @event_data: event data payload
- * fw_event:
+ * @fw_event: The fw_event_work object
* Context: user.
*
*/
static void
-_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataSasTopologyChangeList_t *event_data,
+_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc,
struct fw_event_work *fw_event)
{
int i;
@@ -3816,18 +4158,24 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
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
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_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 "
@@ -3842,6 +4190,17 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
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) {
@@ -3851,57 +4210,57 @@ _scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
}
if (ioc->shost_recovery)
return;
- if (event_data->PHY[i].PhyStatus &
- MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT)
+ phy_number = event_data->StartPhyNum + i;
+ reason_code = event_data->PHY[i].PhyStatus &
+ MPI2_EVENT_SAS_TOPO_RC_MASK;
+ if ((event_data->PHY[i].PhyStatus &
+ MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code !=
+ MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING))
continue;
handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle);
if (!handle)
continue;
- phy_number = event_data->StartPhyNum + i;
- reason_code = event_data->PHY[i].PhyStatus &
- MPI2_EVENT_SAS_TOPO_RC_MASK;
- 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);
}
@@ -3953,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;
@@ -3971,20 +4336,52 @@ _scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_device_status_change_event - handle device status change
* @ioc: per adapter object
- * @VF_ID:
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataSasDeviceStatusChange_t *event_data)
+_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, event_data);
+ _scsih_sas_device_status_change_event_debug(ioc,
+ 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
@@ -4026,34 +4423,33 @@ _scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_enclosure_dev_status_change_event - handle enclosure events
* @ioc: per adapter object
- * @VF_ID:
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc,
- u8 VF_ID, Mpi2EventDataSasEnclDevStatusChange_t *event_data)
+ struct fw_event_work *fw_event)
{
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
_scsih_sas_enclosure_dev_status_change_event_debug(ioc,
- event_data);
+ fw_event->event_data);
#endif
}
/**
* _scsih_sas_broadcast_primative_event - handle broadcast events
* @ioc: per adapter object
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataSasBroadcastPrimitive_t *event_data)
+_scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
struct scsi_cmnd *scmd;
u16 smid, handle;
@@ -4062,11 +4458,13 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
u32 termination_count;
u32 query_count;
Mpi2SCSITaskManagementReply_t *mpi_reply;
-
+#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));
-
dtmprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s: enter\n", ioc->name,
__func__));
@@ -4074,7 +4472,7 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
termination_count = 0;
query_count = 0;
mpi_reply = ioc->tm_cmds.reply;
- for (smid = 1; smid <= ioc->request_depth; smid++) {
+ for (smid = 1; smid <= ioc->scsiio_depth; smid++) {
scmd = _scsih_scsi_lookup_get(ioc, smid);
if (!scmd)
continue;
@@ -4097,8 +4495,9 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
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 ==
@@ -4121,23 +4520,25 @@ _scsih_sas_broadcast_primative_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
/**
* _scsih_sas_discovery_event - handle discovery events
* @ioc: per adapter object
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataSasDiscovery_t *event_data)
+_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
+ Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data;
+
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) {
printk(MPT2SAS_DEBUG_FMT "discovery event: (%s)", ioc->name,
(event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ?
"start" : "stop");
if (event_data->DiscoveryStatus)
- printk(MPT2SAS_DEBUG_FMT ", discovery_status(0x%08x)",
- ioc->name, le32_to_cpu(event_data->DiscoveryStatus));
+ printk("discovery_status(0x%08x)",
+ le32_to_cpu(event_data->DiscoveryStatus));
printk("\n");
}
#endif
@@ -4351,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);
}
/**
@@ -4372,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);
@@ -4396,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);
}
@@ -4488,19 +4892,19 @@ _scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_ir_config_change_event - handle ir configuration change events
* @ioc: per adapter object
- * @VF_ID:
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataIrConfigChangeList_t *event_data)
+_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
Mpi2EventIrConfigElement_t *element;
int i;
u8 foreign_config;
+ Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data;
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
@@ -4543,14 +4947,14 @@ _scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
/**
* _scsih_sas_ir_volume_event - IR volume event
* @ioc: per adapter object
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataIrVolume_t *event_data)
+_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
u64 wwid;
unsigned long flags;
@@ -4559,6 +4963,7 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
u32 state;
int rc;
struct MPT2SAS_TARGET *sas_target_priv_data;
+ Mpi2EventDataIrVolume_t *event_data = fw_event->event_data;
if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED)
return;
@@ -4628,22 +5033,24 @@ _scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
/**
* _scsih_sas_ir_physical_disk_event - PD event
* @ioc: per adapter object
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataIrPhysicalDisk_t *event_data)
+_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;
Mpi2ConfigReply_t mpi_reply;
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;
@@ -4685,9 +5092,10 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
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);
@@ -4727,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,
@@ -4743,33 +5157,33 @@ _scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc,
/**
* _scsih_sas_ir_operation_status_event - handle RAID operation events
* @ioc: per adapter object
- * @VF_ID:
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Return nothing.
*/
static void
-_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataIrOperationStatus_t *event_data)
+_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc,
+ struct fw_event_work *fw_event)
{
#ifdef CONFIG_SCSI_MPT2SAS_LOGGING
if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK)
- _scsih_sas_ir_operation_status_event_debug(ioc, event_data);
+ _scsih_sas_ir_operation_status_event_debug(ioc,
+ fw_event->event_data);
#endif
}
/**
* _scsih_task_set_full - handle task set full
* @ioc: per adapter object
- * @event_data: event data payload
+ * @fw_event: The fw_event_work object
* Context: user.
*
* Throttle back qdepth.
*/
static void
-_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
- Mpi2EventDataTaskSetFull_t *event_data)
+_scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work
+ *fw_event)
{
unsigned long flags;
struct _sas_device *sas_device;
@@ -4780,6 +5194,7 @@ _scsih_task_set_full(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID,
u16 handle;
int id, channel;
u64 sas_address;
+ Mpi2EventDataTaskSetFull_t *event_data = fw_event->event_data;
current_depth = le16_to_cpu(event_data->CurrentDepth);
handle = le16_to_cpu(event_data->DevHandle);
@@ -4868,6 +5283,10 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
if (sas_device->sas_address == sas_address &&
sas_device->slot == slot && sas_device->starget) {
sas_device->responding = 1;
+ sas_device->state = 0;
+ starget = sas_device->starget;
+ sas_target_priv_data = starget->hostdata;
+ sas_target_priv_data->tm_busy = 0;
starget_printk(KERN_INFO, sas_device->starget,
"handle(0x%04x), sas_addr(0x%016llx), enclosure "
"logical id(0x%016llx), slot(%d)\n", handle,
@@ -4880,8 +5299,6 @@ _scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address,
printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n",
sas_device->handle);
sas_device->handle = handle;
- starget = sas_device->starget;
- sas_target_priv_data = starget->hostdata;
sas_target_priv_data->handle = handle;
goto out;
}
@@ -5028,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);
@@ -5116,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,
@@ -5142,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;
}
}
@@ -5182,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);
@@ -5227,44 +5651,38 @@ _firmware_event_work(struct work_struct *work)
switch (fw_event->event) {
case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST:
- _scsih_sas_topology_change_event(ioc, fw_event->VF_ID,
- fw_event->event_data, fw_event);
+ _scsih_sas_topology_change_event(ioc, fw_event);
break;
case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE:
- _scsih_sas_device_status_change_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_device_status_change_event(ioc,
+ fw_event);
break;
case MPI2_EVENT_SAS_DISCOVERY:
- _scsih_sas_discovery_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_discovery_event(ioc,
+ fw_event);
break;
case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE:
- _scsih_sas_broadcast_primative_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_broadcast_primative_event(ioc,
+ fw_event);
break;
case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE:
_scsih_sas_enclosure_dev_status_change_event(ioc,
- fw_event->VF_ID, fw_event->event_data);
+ fw_event);
break;
case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST:
- _scsih_sas_ir_config_change_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_ir_config_change_event(ioc, fw_event);
break;
case MPI2_EVENT_IR_VOLUME:
- _scsih_sas_ir_volume_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_ir_volume_event(ioc, fw_event);
break;
case MPI2_EVENT_IR_PHYSICAL_DISK:
- _scsih_sas_ir_physical_disk_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_ir_physical_disk_event(ioc, fw_event);
break;
case MPI2_EVENT_IR_OPERATION_STATUS:
- _scsih_sas_ir_operation_status_event(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_sas_ir_operation_status_event(ioc, fw_event);
break;
case MPI2_EVENT_TASK_SET_FULL:
- _scsih_task_set_full(ioc, fw_event->VF_ID,
- fw_event->event_data);
+ _scsih_task_set_full(ioc, fw_event);
break;
}
_scsih_fw_event_free(ioc, fw_event);
@@ -5273,17 +5691,19 @@ _firmware_event_work(struct work_struct *work)
/**
* mpt2sas_scsih_event_callback - firmware event handler (called at ISR time)
* @ioc: per adapter object
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
* Context: interrupt.
*
* This function merely adds a new work task into ioc->firmware_event_thread.
* The tasks are worked from _firmware_event_work in user context.
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
+u8
+mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
+ u32 reply)
{
struct fw_event_work *fw_event;
Mpi2EventNotificationReply_t *mpi_reply;
@@ -5294,11 +5714,11 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
spin_lock_irqsave(&ioc->fw_event_lock, flags);
if (ioc->fw_events_off || ioc->remove_host) {
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
- return;
+ return 1;
}
spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
- mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
+ mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply);
event = le16_to_cpu(mpi_reply->Event);
switch (event) {
@@ -5312,7 +5732,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
if (baen_data->Primitive !=
MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT ||
ioc->broadcast_aen_busy)
- return;
+ return 1;
ioc->broadcast_aen_busy = 1;
break;
}
@@ -5334,14 +5754,14 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
break;
default: /* ignore the rest */
- return;
+ return 1;
}
fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC);
if (!fw_event) {
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
- return;
+ return 1;
}
fw_event->event_data =
kzalloc(mpi_reply->EventDataLength*4, GFP_ATOMIC);
@@ -5349,15 +5769,17 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 VF_ID, u32 reply)
printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n",
ioc->name, __FILE__, __LINE__, __func__);
kfree(fw_event);
- return;
+ return 1;
}
memcpy(fw_event->event_data, mpi_reply->EventData,
mpi_reply->EventDataLength*4);
fw_event->ioc = ioc;
- fw_event->VF_ID = VF_ID;
+ fw_event->VF_ID = mpi_reply->VF_ID;
+ fw_event->VP_ID = mpi_reply->VP_ID;
fw_event->event = event;
_scsih_fw_event_add(ioc, fw_event);
+ return 1;
}
/* shost template */
@@ -5424,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;
@@ -5447,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;
@@ -5455,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,
@@ -5468,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
@@ -5504,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 {
@@ -5513,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;
}
}
@@ -5527,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);
@@ -5548,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;
@@ -5577,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);
}
}
@@ -5617,7 +6131,7 @@ _scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc)
}
/**
- * _scsih_probe_sas - reporting raid volumes to sas transport
+ * _scsih_probe_sas - reporting sas devices to sas transport
* @ioc: per adapter object
*
* Called during initial loading of the driver.
@@ -5627,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,
@@ -5637,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);
}
}
@@ -5713,7 +6224,10 @@ _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;
ioc->logging_level = logging_level;
/* misc semaphores and spin locks */
spin_lock_init(&ioc->ioc_reset_in_progress_lock);
@@ -5729,6 +6243,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
INIT_LIST_HEAD(&ioc->fw_event_list);
INIT_LIST_HEAD(&ioc->raid_device_list);
INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list);
+ INIT_LIST_HEAD(&ioc->delayed_tr_list);
/* init shost parameters */
shost->max_cmd_len = 16;
@@ -5745,6 +6260,7 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION
| SHOST_DIF_TYPE3_PROTECTION);
+ scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC);
/* event thread */
snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name),
@@ -5846,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,
@@ -5887,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);
@@ -5894,6 +6414,11 @@ _scsih_init(void)
/* ctl module callback handler */
ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done);
+ tm_tr_cb_idx = mpt2sas_base_register_callback_handler(
+ _scsih_tm_tr_complete);
+ tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler(
+ _scsih_sas_control_complete);
+
mpt2sas_ctl_init();
error = pci_register_driver(&scsih_driver);
@@ -5921,9 +6446,13 @@ _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);
+ mpt2sas_base_release_callback_handler(tm_tr_cb_idx);
+ mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx);
+
mpt2sas_ctl_exit();
}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index 742324a0a11e..3a82872bad44 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -2,7 +2,7 @@
* SAS Transport Layer for MPT (Message Passing Technology) based controllers
*
* This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
- * Copyright (C) 2007-2008 LSI Corporation
+ * Copyright (C) 2007-2009 LSI Corporation
* (mailto:DL-MPTFusionLinux@lsi.com)
*
* This program is free software; you can redistribute it and/or
@@ -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);
}
/**
@@ -212,25 +211,26 @@ _transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle,
* mpt2sas_transport_done - internal transport layer callback handler.
* @ioc: per adapter object
* @smid: system request message index
- * @VF_ID: virtual function id
+ * @msix_index: MSIX table index supplied by the OS
* @reply: reply message frame(lower 32bit addr)
*
* Callback handler when sending internal generated transport cmds.
* The callback index passed is `ioc->transport_cb_idx`
*
- * Return nothing.
+ * Return 1 meaning mf should be freed from _base_interrupt
+ * 0 means the mf is freed from this function.
*/
-void
-mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
+u8
+mpt2sas_transport_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->transport_cmds.status == MPT2_CMD_NOT_USED)
- return;
+ return 1;
if (ioc->transport_cmds.smid != smid)
- return;
+ return 1;
ioc->transport_cmds.status |= MPT2_CMD_COMPLETE;
if (mpi_reply) {
memcpy(ioc->transport_cmds.reply, mpi_reply,
@@ -239,6 +239,7 @@ mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 VF_ID,
}
ioc->transport_cmds.status &= ~MPT2_CMD_PENDING;
complete(&ioc->transport_cmds.done);
+ return 1;
}
/* report manufacture request structure */
@@ -257,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];
@@ -369,9 +369,12 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
mpi_request->PhysicalPort = 0xFF;
+ mpi_request->VF_ID = 0; /* TODO */
+ 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 */
@@ -396,7 +399,8 @@ _transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc,
dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "report_manufacture - "
"send to sas_addr(0x%016llx)\n", ioc->name,
(unsigned long long)sas_address));
- mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->transport_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
10*HZ);
@@ -433,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);
@@ -464,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.
@@ -473,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;
@@ -483,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) {
@@ -497,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",
@@ -599,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
@@ -609,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;
@@ -619,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;
@@ -645,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);
@@ -794,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
*
@@ -803,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
@@ -836,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);
}
@@ -1106,6 +1101,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t));
mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH;
mpi_request->PhysicalPort = 0xFF;
+ mpi_request->VF_ID = 0; /* TODO */
+ mpi_request->VP_ID = 0;
*((u64 *)&mpi_request->SASAddress) = (rphy) ?
cpu_to_le64(rphy->identify.sas_address) :
cpu_to_le64(ioc->sas_hba.sas_address);
@@ -1119,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;
}
@@ -1137,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;
}
@@ -1147,7 +1144,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
dtransportprintk(ioc, printk(MPT2SAS_DEBUG_FMT "%s - "
"sending smp request\n", ioc->name, __func__));
- mpt2sas_base_put_smid_default(ioc, smid, 0 /* VF_ID */);
+ mpt2sas_base_put_smid_default(ioc, smid);
+ init_completion(&ioc->transport_cmds.done);
timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done,
10*HZ);
diff --git a/drivers/scsi/mvsas/mv_defs.h b/drivers/scsi/mvsas/mv_defs.h
index f8cb9defb961..1849da1f030d 100644
--- a/drivers/scsi/mvsas/mv_defs.h
+++ b/drivers/scsi/mvsas/mv_defs.h
@@ -25,6 +25,8 @@
#ifndef _MV_DEFS_H_
#define _MV_DEFS_H_
+#define PCI_DEVICE_ID_ARECA_1300 0x1300
+#define PCI_DEVICE_ID_ARECA_1320 0x1320
enum chip_flavors {
chip_6320,
@@ -32,6 +34,8 @@ enum chip_flavors {
chip_6485,
chip_9480,
chip_9180,
+ chip_1300,
+ chip_1320
};
/* driver compile-time configuration */
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index 8646a19f999d..c790d45876c4 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -32,6 +32,8 @@ static const struct mvs_chip_info mvs_chips[] = {
[chip_6485] = { 1, 8, 0x800, 33, 32, 10, &mvs_64xx_dispatch, },
[chip_9180] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, },
[chip_9480] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, },
+ [chip_1300] = { 1, 4, 0x400, 17, 16, 9, &mvs_64xx_dispatch, },
+ [chip_1320] = { 2, 4, 0x800, 17, 64, 9, &mvs_94xx_dispatch, },
};
#define SOC_SAS_NUM 2
@@ -653,6 +655,8 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = {
{ PCI_VDEVICE(MARVELL, 0x6485), chip_6485 },
{ PCI_VDEVICE(MARVELL, 0x9480), chip_9480 },
{ PCI_VDEVICE(MARVELL, 0x9180), chip_9180 },
+ { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 },
+ { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 },
{ } /* terminate list */
};
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 4302f06e4ec9..f7c70e2a8224 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -46,6 +46,7 @@
#include <linux/mutex.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_cmnd.h>
@@ -684,7 +685,7 @@ static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd)
struct pmcraid_instance *pinstance = cmd->drv_inst;
unsigned long lock_flags;
- dev_err(&pinstance->pdev->dev,
+ dev_info(&pinstance->pdev->dev,
"Adapter being reset due to command timeout.\n");
/* Command timeouts result in hard reset sequence. The command that got
@@ -815,8 +816,9 @@ static void pmcraid_erp_done(struct pmcraid_cmd *cmd)
if (PMCRAID_IOASC_SENSE_KEY(ioasc) > 0) {
scsi_cmd->result |= (DID_ERROR << 16);
- pmcraid_err("command CDB[0] = %x failed with IOASC: 0x%08X\n",
- cmd->ioa_cb->ioarcb.cdb[0], ioasc);
+ scmd_printk(KERN_INFO, scsi_cmd,
+ "command CDB[0] = %x failed with IOASC: 0x%08X\n",
+ cmd->ioa_cb->ioarcb.cdb[0], ioasc);
}
/* if we had allocated sense buffers for request sense, copy the sense
@@ -1541,13 +1543,13 @@ static void pmcraid_handle_error_log(struct pmcraid_instance *pinstance)
if (pinstance->ldn.hcam->notification_lost ==
HOSTRCB_NOTIFICATIONS_LOST)
- dev_err(&pinstance->pdev->dev, "Error notifications lost\n");
+ dev_info(&pinstance->pdev->dev, "Error notifications lost\n");
ioasc = le32_to_cpu(hcam_ldn->error_log.fd_ioasc);
if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET ||
ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER) {
- dev_err(&pinstance->pdev->dev,
+ dev_info(&pinstance->pdev->dev,
"UnitAttention due to IOA Bus Reset\n");
scsi_report_bus_reset(
pinstance->host,
@@ -1584,7 +1586,7 @@ static void pmcraid_process_ccn(struct pmcraid_cmd *cmd)
atomic_read(&pinstance->ccn.ignore) == 1) {
return;
} else if (ioasc) {
- dev_err(&pinstance->pdev->dev,
+ dev_info(&pinstance->pdev->dev,
"Host RCB (CCN) failed with IOASC: 0x%08X\n", ioasc);
spin_lock_irqsave(pinstance->host->host_lock, lock_flags);
pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE);
@@ -1634,7 +1636,7 @@ static void pmcraid_process_ldn(struct pmcraid_cmd *cmd)
return;
}
} else {
- dev_err(&pinstance->pdev->dev,
+ dev_info(&pinstance->pdev->dev,
"Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc);
}
/* send netlink message for HCAM notification if enabled */
@@ -1822,7 +1824,6 @@ static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance)
scsi_dma_unmap(scsi_cmd);
pmcraid_return_cmd(cmd);
-
pmcraid_info("failing(%d) CDB[0] = %x result: %x\n",
le32_to_cpu(resp) >> 2,
cmd->ioa_cb->ioarcb.cdb[0],
@@ -2514,7 +2515,8 @@ static int pmcraid_reset_device(
res = scsi_cmd->device->hostdata;
if (!res) {
- pmcraid_err("reset_device: NULL resource pointer\n");
+ sdev_printk(KERN_ERR, scsi_cmd->device,
+ "reset_device: NULL resource pointer\n");
return FAILED;
}
@@ -2752,8 +2754,8 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd)
pinstance =
(struct pmcraid_instance *)scsi_cmd->device->host->hostdata;
- dev_err(&pinstance->pdev->dev,
- "I/O command timed out, aborting it.\n");
+ scmd_printk(KERN_INFO, scsi_cmd,
+ "I/O command timed out, aborting it.\n");
res = scsi_cmd->device->hostdata;
@@ -2824,7 +2826,8 @@ static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd)
*/
static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd)
{
- pmcraid_err("Doing device reset due to an I/O command timeout.\n");
+ scmd_printk(KERN_INFO, scmd,
+ "resetting device due to an I/O command timeout.\n");
return pmcraid_reset_device(scmd,
PMCRAID_INTERNAL_TIMEOUT,
RESET_DEVICE_LUN);
@@ -2832,7 +2835,8 @@ static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd)
static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd)
{
- pmcraid_err("Doing bus reset due to an I/O command timeout.\n");
+ scmd_printk(KERN_INFO, scmd,
+ "Doing bus reset due to an I/O command timeout.\n");
return pmcraid_reset_device(scmd,
PMCRAID_RESET_BUS_TIMEOUT,
RESET_DEVICE_BUS);
@@ -2840,7 +2844,8 @@ static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd)
static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd)
{
- pmcraid_err("Doing target reset due to an I/O command timeout.\n");
+ scmd_printk(KERN_INFO, scmd,
+ "Doing target reset due to an I/O command timeout.\n");
return pmcraid_reset_device(scmd,
PMCRAID_INTERNAL_TIMEOUT,
RESET_DEVICE_TARGET);
@@ -2988,11 +2993,11 @@ static int pmcraid_build_ioadl(
nseg = scsi_dma_map(scsi_cmd);
if (nseg < 0) {
- dev_err(&pinstance->pdev->dev, "scsi_map_dma failed!\n");
+ scmd_printk(KERN_ERR, scsi_cmd, "scsi_map_dma failed!\n");
return -1;
} else if (nseg > PMCRAID_MAX_IOADLS) {
scsi_dma_unmap(scsi_cmd);
- dev_err(&pinstance->pdev->dev,
+ scmd_printk(KERN_ERR, scsi_cmd,
"sg count is (%d) more than allowed!\n", nseg);
return -1;
}
@@ -5040,7 +5045,7 @@ static int pmcraid_resume(struct pci_dev *pdev)
rc = pci_enable_device(pdev);
if (rc) {
- pmcraid_err("pmcraid: Enable device failed\n");
+ dev_err(&pdev->dev, "resume: Enable device failed\n");
return rc;
}
@@ -5054,7 +5059,7 @@ static int pmcraid_resume(struct pci_dev *pdev)
rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (rc != 0) {
- dev_err(&pdev->dev, "Failed to set PCI DMA mask\n");
+ dev_err(&pdev->dev, "resume: Failed to set PCI DMA mask\n");
goto disable_device;
}
@@ -5063,7 +5068,8 @@ static int pmcraid_resume(struct pci_dev *pdev)
rc = pmcraid_register_interrupt_handler(pinstance);
if (rc) {
- pmcraid_err("resume: couldn't register interrupt handlers\n");
+ dev_err(&pdev->dev,
+ "resume: couldn't register interrupt handlers\n");
rc = -ENODEV;
goto release_host;
}
@@ -5080,7 +5086,7 @@ static int pmcraid_resume(struct pci_dev *pdev)
* state.
*/
if (pmcraid_reset_bringup(pinstance)) {
- pmcraid_err("couldn't initialize IOA \n");
+ dev_err(&pdev->dev, "couldn't initialize IOA \n");
rc = -ENODEV;
goto release_tasklets;
}
@@ -5187,7 +5193,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
LIST_HEAD(old_res);
if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED)
- dev_err(&pinstance->pdev->dev, "Require microcode download\n");
+ pmcraid_err("IOA requires microcode download\n");
/* resource list is protected by pinstance->resource_lock.
* init_res_table can be called from probe (user-thread) or runtime
@@ -5224,8 +5230,7 @@ static void pmcraid_init_res_table(struct pmcraid_cmd *cmd)
if (!found) {
if (list_empty(&pinstance->free_res_q)) {
- dev_err(&pinstance->pdev->dev,
- "Too many devices attached\n");
+ pmcraid_err("Too many devices attached\n");
break;
}
@@ -5442,7 +5447,7 @@ static int __devinit pmcraid_probe(
rc = pmcraid_register_interrupt_handler(pinstance);
if (rc) {
- pmcraid_err("couldn't register interrupt handler\n");
+ dev_err(&pdev->dev, "couldn't register interrupt handler\n");
goto out_scsi_host_put;
}
@@ -5466,7 +5471,7 @@ static int __devinit pmcraid_probe(
*/
pmcraid_info("starting IOA initialization sequence\n");
if (pmcraid_reset_bringup(pinstance)) {
- pmcraid_err("couldn't initialize IOA \n");
+ dev_err(&pdev->dev, "couldn't initialize IOA \n");
rc = 1;
goto out_release_bufs;
}
@@ -5534,7 +5539,6 @@ static struct pci_driver pmcraid_driver = {
.shutdown = pmcraid_shutdown
};
-
/**
* pmcraid_init - module load entry point
*/
@@ -5566,7 +5570,6 @@ static int __init pmcraid_init(void)
goto out_unreg_chrdev;
}
-
error = pmcraid_netlink_init();
if (error)
@@ -5584,6 +5587,7 @@ static int __init pmcraid_init(void)
out_unreg_chrdev:
unregister_chrdev_region(MKDEV(pmcraid_major, 0), PMCRAID_MAX_ADAPTERS);
+
out_init:
return error;
}
diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c
index 42b799abba57..e07b3617f019 100644
--- a/drivers/scsi/qla2xxx/qla_mid.c
+++ b/drivers/scsi/qla2xxx/qla_mid.c
@@ -568,7 +568,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
if (req == NULL) {
qla_printk(KERN_WARNING, ha, "could not allocate memory"
"for request que\n");
- goto que_failed;
+ goto failed;
}
req->length = REQUEST_ENTRY_CNT_24XX;
@@ -632,6 +632,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
que_failed:
qla25xx_free_req_que(base_vha, req);
+failed:
return 0;
}
@@ -659,7 +660,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
if (rsp == NULL) {
qla_printk(KERN_WARNING, ha, "could not allocate memory for"
" response que\n");
- goto que_failed;
+ goto failed;
}
rsp->length = RESPONSE_ENTRY_CNT_MQ;
@@ -728,6 +729,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
que_failed:
qla25xx_free_rsp_que(base_vha, rsp);
+failed:
return 0;
}
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index b6e03074cb8f..dd098cad337b 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -241,10 +241,7 @@ scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask)
*/
struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
{
- struct scsi_cmnd *cmd;
- unsigned char *buf;
-
- cmd = scsi_host_alloc_command(shost, gfp_mask);
+ struct scsi_cmnd *cmd = scsi_host_alloc_command(shost, gfp_mask);
if (unlikely(!cmd)) {
unsigned long flags;
@@ -258,9 +255,15 @@ struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask)
spin_unlock_irqrestore(&shost->free_list_lock, flags);
if (cmd) {
+ void *buf, *prot;
+
buf = cmd->sense_buffer;
+ prot = cmd->prot_sdb;
+
memset(cmd, 0, sizeof(*cmd));
+
cmd->sense_buffer = buf;
+ cmd->prot_sdb = prot;
}
}
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index fb9af207d61d..c4103bef41b5 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -50,6 +50,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsicam.h>
#include <scsi/scsi_eh.h>
+#include <scsi/scsi_dbg.h>
#include "sd.h"
#include "scsi_logging.h"
@@ -64,6 +65,7 @@ static const char * scsi_debug_version_date = "20070104";
#define PARAMETER_LIST_LENGTH_ERR 0x1a
#define INVALID_OPCODE 0x20
#define ADDR_OUT_OF_RANGE 0x21
+#define INVALID_COMMAND_OPCODE 0x20
#define INVALID_FIELD_IN_CDB 0x24
#define INVALID_FIELD_IN_PARAM_LIST 0x26
#define POWERON_RESET 0x29
@@ -180,7 +182,7 @@ static int sdebug_sectors_per; /* sectors per cylinder */
#define SDEBUG_SENSE_LEN 32
#define SCSI_DEBUG_CANQUEUE 255
-#define SCSI_DEBUG_MAX_CMD_LEN 16
+#define SCSI_DEBUG_MAX_CMD_LEN 32
struct sdebug_dev_info {
struct list_head dev_list;
@@ -296,9 +298,25 @@ static void mk_sense_buffer(struct sdebug_dev_info *devip, int key,
}
static void get_data_transfer_info(unsigned char *cmd,
- unsigned long long *lba, unsigned int *num)
+ unsigned long long *lba, unsigned int *num,
+ u32 *ei_lba)
{
+ *ei_lba = 0;
+
switch (*cmd) {
+ case VARIABLE_LENGTH_CMD:
+ *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
+ (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
+ (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
+ (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
+
+ *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
+ (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
+
+ *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
+ (u32)cmd[28] << 24;
+ break;
+
case WRITE_16:
case READ_16:
*lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
@@ -1589,7 +1607,7 @@ static int do_device_access(struct scsi_cmnd *scmd,
}
static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
- unsigned int sectors)
+ unsigned int sectors, u32 ei_lba)
{
unsigned int i, resid;
struct scatterlist *psgl;
@@ -1636,13 +1654,23 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
return 0x01;
}
- if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
+ if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) {
printk(KERN_ERR "%s: REF check failed on sector %lu\n",
__func__, (unsigned long)sector);
dif_errors++;
return 0x03;
}
+
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ be32_to_cpu(sdt[i].ref_tag) != ei_lba) {
+ printk(KERN_ERR "%s: REF check failed on sector %lu\n",
+ __func__, (unsigned long)sector);
+ dif_errors++;
+ return 0x03;
+ }
+
+ ei_lba++;
}
resid = sectors * 8; /* Bytes of protection data to copy into sgl */
@@ -1670,7 +1698,8 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
}
static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
- unsigned int num, struct sdebug_dev_info *devip)
+ unsigned int num, struct sdebug_dev_info *devip,
+ u32 ei_lba)
{
unsigned long iflags;
int ret;
@@ -1699,7 +1728,7 @@ static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
/* DIX + T10 DIF */
if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
- int prot_ret = prot_verify_read(SCpnt, lba, num);
+ int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
if (prot_ret) {
mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret);
@@ -1735,7 +1764,7 @@ void dump_sector(unsigned char *buf, int len)
}
static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
- unsigned int sectors)
+ unsigned int sectors, u32 ei_lba)
{
int i, j, ret;
struct sd_dif_tuple *sdt;
@@ -1749,11 +1778,6 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
sector = do_div(tmp_sec, sdebug_store_sectors);
- if (((SCpnt->cmnd[1] >> 5) & 7) != 1) {
- printk(KERN_WARNING "scsi_debug: WRPROTECT != 1\n");
- return 0;
- }
-
BUG_ON(scsi_sg_count(SCpnt) == 0);
BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
@@ -1808,7 +1832,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
goto out;
}
- if (scsi_debug_dif != SD_DIF_TYPE3_PROTECTION &&
+ if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION &&
be32_to_cpu(sdt->ref_tag)
!= (start_sec & 0xffffffff)) {
printk(KERN_ERR
@@ -1819,6 +1843,16 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
goto out;
}
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ be32_to_cpu(sdt->ref_tag) != ei_lba) {
+ printk(KERN_ERR
+ "%s: REF check failed on sector %lu\n",
+ __func__, (unsigned long)sector);
+ ret = 0x03;
+ dump_sector(daddr, scsi_debug_sector_size);
+ goto out;
+ }
+
/* Would be great to copy this in bigger
* chunks. However, for the sake of
* correctness we need to verify each sector
@@ -1832,6 +1866,7 @@ static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
sector = 0; /* Force wrap */
start_sec++;
+ ei_lba++;
daddr += scsi_debug_sector_size;
ppage_offset += sizeof(struct sd_dif_tuple);
}
@@ -1853,7 +1888,8 @@ out:
}
static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
- unsigned int num, struct sdebug_dev_info *devip)
+ unsigned int num, struct sdebug_dev_info *devip,
+ u32 ei_lba)
{
unsigned long iflags;
int ret;
@@ -1864,7 +1900,7 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
/* DIX + T10 DIF */
if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
- int prot_ret = prot_verify_write(SCpnt, lba, num);
+ int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
if (prot_ret) {
mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret);
@@ -2872,11 +2908,12 @@ static int __init scsi_debug_init(void)
case SD_DIF_TYPE0_PROTECTION:
case SD_DIF_TYPE1_PROTECTION:
+ case SD_DIF_TYPE2_PROTECTION:
case SD_DIF_TYPE3_PROTECTION:
break;
default:
- printk(KERN_ERR "scsi_debug_init: dif must be 0, 1 or 3\n");
+ printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n");
return -EINVAL;
}
@@ -3121,6 +3158,7 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
int len, k;
unsigned int num;
unsigned long long lba;
+ u32 ei_lba;
int errsts = 0;
int target = SCpnt->device->id;
struct sdebug_dev_info *devip = NULL;
@@ -3254,14 +3292,30 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
case READ_16:
case READ_12:
case READ_10:
+ /* READ{10,12,16} and DIF Type 2 are natural enemies */
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ cmd[1] & 0xe0) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_COMMAND_OPCODE, 0);
+ errsts = check_condition_result;
+ break;
+ }
+
+ if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
+ scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
+ (cmd[1] & 0xe0) == 0)
+ printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
+
+ /* fall through */
case READ_6:
+read:
errsts = check_readiness(SCpnt, 0, devip);
if (errsts)
break;
if (scsi_debug_fake_rw)
break;
- get_data_transfer_info(cmd, &lba, &num);
- errsts = resp_read(SCpnt, lba, num, devip);
+ get_data_transfer_info(cmd, &lba, &num, &ei_lba);
+ errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
if (inj_recovered && (0 == errsts)) {
mk_sense_buffer(devip, RECOVERED_ERROR,
THRESHOLD_EXCEEDED, 0);
@@ -3288,14 +3342,30 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
case WRITE_16:
case WRITE_12:
case WRITE_10:
+ /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ cmd[1] & 0xe0) {
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_COMMAND_OPCODE, 0);
+ errsts = check_condition_result;
+ break;
+ }
+
+ if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
+ scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
+ (cmd[1] & 0xe0) == 0)
+ printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
+
+ /* fall through */
case WRITE_6:
+write:
errsts = check_readiness(SCpnt, 0, devip);
if (errsts)
break;
if (scsi_debug_fake_rw)
break;
- get_data_transfer_info(cmd, &lba, &num);
- errsts = resp_write(SCpnt, lba, num, devip);
+ get_data_transfer_info(cmd, &lba, &num, &ei_lba);
+ errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
if (inj_recovered && (0 == errsts)) {
mk_sense_buffer(devip, RECOVERED_ERROR,
THRESHOLD_EXCEEDED, 0);
@@ -3341,15 +3411,38 @@ int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done)
break;
if (scsi_debug_fake_rw)
break;
- get_data_transfer_info(cmd, &lba, &num);
- errsts = resp_read(SCpnt, lba, num, devip);
+ get_data_transfer_info(cmd, &lba, &num, &ei_lba);
+ errsts = resp_read(SCpnt, lba, num, devip, ei_lba);
if (errsts)
break;
- errsts = resp_write(SCpnt, lba, num, devip);
+ errsts = resp_write(SCpnt, lba, num, devip, ei_lba);
if (errsts)
break;
errsts = resp_xdwriteread(SCpnt, lba, num, devip);
break;
+ case VARIABLE_LENGTH_CMD:
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
+
+ if ((cmd[10] & 0xe0) == 0)
+ printk(KERN_ERR
+ "Unprotected RD/WR to DIF device\n");
+
+ if (cmd[9] == READ_32) {
+ BUG_ON(SCpnt->cmd_len < 32);
+ goto read;
+ }
+
+ if (cmd[9] == WRITE_32) {
+ BUG_ON(SCpnt->cmd_len < 32);
+ goto write;
+ }
+ }
+
+ mk_sense_buffer(devip, ILLEGAL_REQUEST,
+ INVALID_FIELD_IN_CDB, 0);
+ errsts = check_condition_result;
+ break;
+
default:
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 877204daf549..1b0060b791e8 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -725,6 +725,9 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
case NEEDS_RETRY:
case FAILED:
break;
+ case ADD_TO_MLQUEUE:
+ rtn = NEEDS_RETRY;
+ break;
default:
rtn = FAILED;
break;
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 b98885de6876..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);
}
@@ -3586,6 +3602,7 @@ enum fc_dispatch_result {
/**
* fc_bsg_host_dispatch - process fc host bsg requests and dispatch to LLDD
+ * @q: fc host request queue
* @shost: scsi host rport attached to
* @job: bsg job to be processed
*/
@@ -3693,6 +3710,7 @@ fc_bsg_goose_queue(struct fc_rport *rport)
/**
* fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD
+ * @q: rport request queue
* @shost: scsi host rport attached to
* @rport: rport request destined to
* @job: bsg job to be processed
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 8dd96dcd716c..9093c7261f33 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -116,6 +116,9 @@ static DEFINE_IDA(sd_index_ida);
* object after last put) */
static DEFINE_MUTEX(sd_ref_mutex);
+struct kmem_cache *sd_cdb_cache;
+mempool_t *sd_cdb_pool;
+
static const char *sd_cache_types[] = {
"write through", "none", "write back",
"write back, no read (daft)"
@@ -370,6 +373,31 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
mutex_unlock(&sd_ref_mutex);
}
+static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif)
+{
+ unsigned int prot_op = SCSI_PROT_NORMAL;
+ unsigned int dix = scsi_prot_sg_count(scmd);
+
+ if (scmd->sc_data_direction == DMA_FROM_DEVICE) {
+ if (dif && dix)
+ prot_op = SCSI_PROT_READ_PASS;
+ else if (dif && !dix)
+ prot_op = SCSI_PROT_READ_STRIP;
+ else if (!dif && dix)
+ prot_op = SCSI_PROT_READ_INSERT;
+ } else {
+ if (dif && dix)
+ prot_op = SCSI_PROT_WRITE_PASS;
+ else if (dif && !dix)
+ prot_op = SCSI_PROT_WRITE_INSERT;
+ else if (!dif && dix)
+ prot_op = SCSI_PROT_WRITE_STRIP;
+ }
+
+ scsi_set_prot_op(scmd, prot_op);
+ scsi_set_prot_type(scmd, dif);
+}
+
/**
* sd_init_command - build a scsi (read or write) command from
* information in the request structure.
@@ -388,6 +416,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
sector_t threshold;
unsigned int this_count = blk_rq_sectors(rq);
int ret, host_dif;
+ unsigned char protect;
if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
ret = scsi_setup_blk_pc_cmnd(sdp, rq);
@@ -520,13 +549,49 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
/* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */
host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);
if (host_dif)
- SCpnt->cmnd[1] = 1 << 5;
+ protect = 1 << 5;
else
- SCpnt->cmnd[1] = 0;
+ protect = 0;
- if (block > 0xffffffff) {
+ if (host_dif == SD_DIF_TYPE2_PROTECTION) {
+ SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC);
+
+ if (unlikely(SCpnt->cmnd == NULL)) {
+ ret = BLKPREP_DEFER;
+ goto out;
+ }
+
+ SCpnt->cmd_len = SD_EXT_CDB_SIZE;
+ memset(SCpnt->cmnd, 0, SCpnt->cmd_len);
+ SCpnt->cmnd[0] = VARIABLE_LENGTH_CMD;
+ SCpnt->cmnd[7] = 0x18;
+ SCpnt->cmnd[9] = (rq_data_dir(rq) == READ) ? READ_32 : WRITE_32;
+ SCpnt->cmnd[10] = protect | (blk_fua_rq(rq) ? 0x8 : 0);
+
+ /* LBA */
+ SCpnt->cmnd[12] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0;
+ SCpnt->cmnd[13] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0;
+ SCpnt->cmnd[14] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0;
+ SCpnt->cmnd[15] = sizeof(block) > 4 ? (unsigned char) (block >> 32) & 0xff : 0;
+ SCpnt->cmnd[16] = (unsigned char) (block >> 24) & 0xff;
+ SCpnt->cmnd[17] = (unsigned char) (block >> 16) & 0xff;
+ SCpnt->cmnd[18] = (unsigned char) (block >> 8) & 0xff;
+ SCpnt->cmnd[19] = (unsigned char) block & 0xff;
+
+ /* Expected Indirect LBA */
+ SCpnt->cmnd[20] = (unsigned char) (block >> 24) & 0xff;
+ SCpnt->cmnd[21] = (unsigned char) (block >> 16) & 0xff;
+ SCpnt->cmnd[22] = (unsigned char) (block >> 8) & 0xff;
+ SCpnt->cmnd[23] = (unsigned char) block & 0xff;
+
+ /* Transfer length */
+ SCpnt->cmnd[28] = (unsigned char) (this_count >> 24) & 0xff;
+ SCpnt->cmnd[29] = (unsigned char) (this_count >> 16) & 0xff;
+ SCpnt->cmnd[30] = (unsigned char) (this_count >> 8) & 0xff;
+ SCpnt->cmnd[31] = (unsigned char) this_count & 0xff;
+ } else if (block > 0xffffffff) {
SCpnt->cmnd[0] += READ_16 - READ_6;
- SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0;
+ SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0);
SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0;
SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0;
SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0;
@@ -547,7 +612,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
this_count = 0xffff;
SCpnt->cmnd[0] += READ_10 - READ_6;
- SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0;
+ SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0);
SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
@@ -578,8 +643,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
/* If DIF or DIX is enabled, tell HBA how to handle request */
if (host_dif || scsi_prot_sg_count(SCpnt))
- sd_dif_op(SCpnt, host_dif, scsi_prot_sg_count(SCpnt),
- sdkp->protection_type);
+ sd_prot_op(SCpnt, host_dif);
/*
* We shouldn't disconnect in the middle of a sector, so with a dumb
@@ -1023,6 +1087,7 @@ static int sd_done(struct scsi_cmnd *SCpnt)
int result = SCpnt->result;
unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt);
struct scsi_sense_hdr sshdr;
+ struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk);
int sense_valid = 0;
int sense_deferred = 0;
@@ -1084,6 +1149,10 @@ static int sd_done(struct scsi_cmnd *SCpnt)
if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt))
sd_dif_complete(SCpnt, good_bytes);
+ if (scsi_host_dif_capable(sdkp->device->host, sdkp->protection_type)
+ == SD_DIF_TYPE2_PROTECTION && SCpnt->cmnd != SCpnt->request->cmd)
+ mempool_free(SCpnt->cmnd, sd_cdb_pool);
+
return good_bytes;
}
@@ -1238,34 +1307,28 @@ void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer)
u8 type;
if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0)
- type = 0;
- else
- type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */
+ return;
- sdkp->protection_type = type;
+ type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */
- switch (type) {
- case SD_DIF_TYPE0_PROTECTION:
- case SD_DIF_TYPE1_PROTECTION:
- case SD_DIF_TYPE3_PROTECTION:
- break;
+ if (type == sdkp->protection_type || !sdkp->first_scan)
+ return;
- case SD_DIF_TYPE2_PROTECTION:
- sd_printk(KERN_ERR, sdkp, "formatted with DIF Type 2 " \
- "protection which is currently unsupported. " \
- "Disabling disk!\n");
- goto disable;
+ sdkp->protection_type = type;
- default:
- sd_printk(KERN_ERR, sdkp, "formatted with unknown " \
- "protection type %d. Disabling disk!\n", type);
- goto disable;
+ if (type > SD_DIF_TYPE3_PROTECTION) {
+ sd_printk(KERN_ERR, sdkp, "formatted with unsupported " \
+ "protection type %u. Disabling disk!\n", type);
+ sdkp->capacity = 0;
+ return;
}
- return;
-
-disable:
- sdkp->capacity = 0;
+ if (scsi_host_dif_capable(sdp->host, type))
+ sd_printk(KERN_NOTICE, sdkp,
+ "Enabling DIF Type %u protection\n", type);
+ else
+ sd_printk(KERN_NOTICE, sdkp,
+ "Disabling DIF Type %u protection\n", type);
}
static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
@@ -2300,8 +2363,24 @@ static int __init init_sd(void)
if (err)
goto err_out_class;
+ sd_cdb_cache = kmem_cache_create("sd_ext_cdb", SD_EXT_CDB_SIZE,
+ 0, 0, NULL);
+ if (!sd_cdb_cache) {
+ printk(KERN_ERR "sd: can't init extended cdb cache\n");
+ goto err_out_class;
+ }
+
+ sd_cdb_pool = mempool_create_slab_pool(SD_MEMPOOL_SIZE, sd_cdb_cache);
+ if (!sd_cdb_pool) {
+ printk(KERN_ERR "sd: can't init extended cdb pool\n");
+ goto err_out_cache;
+ }
+
return 0;
+err_out_cache:
+ kmem_cache_destroy(sd_cdb_cache);
+
err_out_class:
class_unregister(&sd_disk_class);
err_out:
@@ -2321,6 +2400,9 @@ static void __exit exit_sd(void)
SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
+ mempool_destroy(sd_cdb_pool);
+ kmem_cache_destroy(sd_cdb_cache);
+
scsi_unregister_driver(&sd_template.gendrv);
class_unregister(&sd_disk_class);
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 8474b5bad3fe..e374804d26fb 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -37,6 +37,11 @@
*/
#define SD_LAST_BUGGY_SECTORS 8
+enum {
+ SD_EXT_CDB_SIZE = 32, /* Extended CDB size */
+ SD_MEMPOOL_SIZE = 2, /* CDB pool size */
+};
+
struct scsi_disk {
struct scsi_driver *driver; /* always &sd_template */
struct scsi_device *device;
@@ -101,16 +106,12 @@ struct sd_dif_tuple {
#ifdef CONFIG_BLK_DEV_INTEGRITY
-extern void sd_dif_op(struct scsi_cmnd *, unsigned int, unsigned int, unsigned int);
extern void sd_dif_config_host(struct scsi_disk *);
extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int);
extern void sd_dif_complete(struct scsi_cmnd *, unsigned int);
#else /* CONFIG_BLK_DEV_INTEGRITY */
-static inline void sd_dif_op(struct scsi_cmnd *cmd, unsigned int a, unsigned int b, unsigned int c)
-{
-}
static inline void sd_dif_config_host(struct scsi_disk *disk)
{
}
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index 82f14a9482d0..88da97745710 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -320,15 +320,6 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
dif = 0; dix = 1;
}
- if (type) {
- if (dif)
- sd_printk(KERN_NOTICE, sdkp,
- "Enabling DIF Type %d protection\n", type);
- else
- sd_printk(KERN_NOTICE, sdkp,
- "Disabling DIF Type %d protection\n", type);
- }
-
if (!dix)
return;
@@ -360,62 +351,6 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
}
/*
- * DIF DMA operation magic decoder ring.
- */
-void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix, unsigned int type)
-{
- int csum_convert, prot_op;
-
- prot_op = 0;
-
- /* Convert checksum? */
- if (scsi_host_get_guard(scmd->device->host) != SHOST_DIX_GUARD_CRC)
- csum_convert = 1;
- else
- csum_convert = 0;
-
- BUG_ON(dif && (scmd->cmnd[0] == READ_6 || scmd->cmnd[0] == WRITE_6));
-
- switch (scmd->cmnd[0]) {
- case READ_6:
- case READ_10:
- case READ_12:
- case READ_16:
- if (dif && dix)
- if (csum_convert)
- prot_op = SCSI_PROT_READ_CONVERT;
- else
- prot_op = SCSI_PROT_READ_PASS;
- else if (dif && !dix)
- prot_op = SCSI_PROT_READ_STRIP;
- else if (!dif && dix)
- prot_op = SCSI_PROT_READ_INSERT;
-
- break;
-
- case WRITE_6:
- case WRITE_10:
- case WRITE_12:
- case WRITE_16:
- if (dif && dix)
- if (csum_convert)
- prot_op = SCSI_PROT_WRITE_CONVERT;
- else
- prot_op = SCSI_PROT_WRITE_PASS;
- else if (dif && !dix)
- prot_op = SCSI_PROT_WRITE_INSERT;
- else if (!dif && dix)
- prot_op = SCSI_PROT_WRITE_STRIP;
-
- break;
- }
-
- scsi_set_prot_op(scmd, prot_op);
- if (dif)
- scsi_set_prot_type(scmd, type);
-}
-
-/*
* The virtual start sector is the one that was originally submitted
* by the block layer. Due to partitioning, MD/DM cloning, etc. the
* actual physical start sector is likely to be different. Remap
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 747a5e5c1276..040f751809ea 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -1708,11 +1708,6 @@ static int sg_finish_rem_req(Sg_request * srp)
Sg_scatter_hold *req_schp = &srp->data;
SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n", (int) srp->res_used));
- if (srp->res_used)
- sg_unlink_reserve(sfp, srp);
- else
- sg_remove_scat(req_schp);
-
if (srp->rq) {
if (srp->bio)
ret = blk_rq_unmap_user(srp->bio);
@@ -1720,6 +1715,11 @@ static int sg_finish_rem_req(Sg_request * srp)
blk_put_request(srp->rq);
}
+ if (srp->res_used)
+ sg_unlink_reserve(sfp, srp);
+ else
+ sg_remove_scat(req_schp);
+
sg_remove_request(sfp, srp);
return ret;
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index eb61f7a70e1d..d6f340f48a3b 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -684,14 +684,20 @@ static void get_sectorsize(struct scsi_cd *cd)
cd->capacity = 0x1fffff;
sector_size = 2048; /* A guess, just in case */
} else {
-#if 0
- if (cdrom_get_last_written(&cd->cdi,
- &cd->capacity))
-#endif
- cd->capacity = 1 + ((buffer[0] << 24) |
- (buffer[1] << 16) |
- (buffer[2] << 8) |
- buffer[3]);
+ long last_written;
+
+ cd->capacity = 1 + ((buffer[0] << 24) | (buffer[1] << 16) |
+ (buffer[2] << 8) | buffer[3]);
+ /*
+ * READ_CAPACITY doesn't return the correct size on
+ * certain UDF media. If last_written is larger, use
+ * it instead.
+ *
+ * http://bugzilla.kernel.org/show_bug.cgi?id=9668
+ */
+ if (!cdrom_get_last_written(&cd->cdi, &last_written))
+ cd->capacity = max_t(long, cd->capacity, last_written);
+
sector_size = (buffer[4] << 24) |
(buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
switch (sector_size) {
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index b33d04250bbc..12d58a7ed6bc 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -2859,11 +2859,8 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon
ioctl_result = st_int_ioctl(STp, MTBSF, 1);
if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
- int old_block_size = STp->block_size;
STp->block_size = arg & MT_ST_BLKSIZE_MASK;
if (STp->block_size != 0) {
- if (old_block_size == 0)
- normalize_buffer(STp->buffer);
(STp->buffer)->buffer_blocks =
(STp->buffer)->buffer_size / STp->block_size;
}
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/serial_core.c b/drivers/serial/serial_core.c
index 1689bda1d13b..dcc72444e8e7 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -1270,6 +1270,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
BUG_ON(!kernel_locked());
+ if (!state)
+ return;
+
uport = state->uart_port;
port = &state->port;
@@ -1316,9 +1319,9 @@ static void uart_close(struct tty_struct *tty, struct file *filp)
*/
if (port->flags & ASYNC_INITIALIZED) {
unsigned long flags;
- spin_lock_irqsave(&port->lock, flags);
+ spin_lock_irqsave(&uport->lock, flags);
uport->ops->stop_rx(uport);
- spin_unlock_irqrestore(&port->lock, flags);
+ spin_unlock_irqrestore(&uport->lock, flags);
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index a3bb49031a7f..ff4617e21426 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -873,10 +873,10 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "cis/PCMLM28.cis"),
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "cis/PCMLM28.cis"),
PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "cis/PCMLM28.cis"),
- PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
- PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
+ PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "cis/DP83903.cis"),
+ PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "cis/DP83903.cis"),
PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "cis/3CCFEM556.cis"),
- PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"),
+ PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "cis/DP83903.cis"),
PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "cis/3CXEM556.cis"),
PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "cis/3CXEM556.cis"),
PCMCIA_DEVICE_CIS_PROD_ID12("Sierra Wireless", "AC850", 0xd85f6206, 0x42a2c018, "SW_8xx_SER.cis"), /* Sierra Wireless AC850 3G Network Adapter R1 */
@@ -884,9 +884,9 @@ static struct pcmcia_device_id serial_ids[] = {
PCMCIA_DEVICE_CIS_MANF_CARD(0x0192, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- pre update */
PCMCIA_DEVICE_CIS_MANF_CARD(0x013f, 0xa555, "SW_555_SER.cis"), /* Sierra Aircard 555 CDMA 1xrtt Modem -- post update */
PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "cis/MT5634ZLX.cis"),
- PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "COMpad2.cis"),
- PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"),
- PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-2", 0x96913a85, 0x27ab5437, "cis/COMpad2.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "cis/COMpad4.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "cis/COMpad2.cis"),
PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "cis/RS-COM-2P.cis"),
PCMCIA_DEVICE_CIS_MANF_CARD(0x0013, 0x0000, "GLOBETROTTER.cis"),
PCMCIA_DEVICE_PROD_ID12("ELAN DIGITAL SYSTEMS LTD, c1997.","SERIAL CARD: SL100 1.00.",0x19ca78af,0xf964f42b),
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/amba-pl022.c b/drivers/spi/amba-pl022.c
index 958a3ffc8987..ff5bbb9c43c9 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -1826,7 +1826,7 @@ static struct amba_id pl022_ids[] = {
* ST Micro derivative, this has 32bit wide
* and 32 locations deep TX/RX FIFO
*/
- .id = 0x00108022,
+ .id = 0x01080022,
.mask = 0xffffffff,
.data = &vendor_st,
},
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/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/staging/Kconfig b/drivers/staging/Kconfig
index 9a4dd5992f65..7df3ba4f1f4d 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -59,8 +59,6 @@ source "drivers/staging/echo/Kconfig"
source "drivers/staging/poch/Kconfig"
-source "drivers/staging/agnx/Kconfig"
-
source "drivers/staging/otus/Kconfig"
source "drivers/staging/rt2860/Kconfig"
@@ -129,7 +127,5 @@ source "drivers/staging/sep/Kconfig"
source "drivers/staging/iio/Kconfig"
-source "drivers/staging/cowloop/Kconfig"
-
endif # !STAGING_EXCLUDE_BUILD
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 104f2f8897ec..747571172269 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -12,7 +12,6 @@ obj-$(CONFIG_W35UND) += winbond/
obj-$(CONFIG_PRISM2_USB) += wlan-ng/
obj-$(CONFIG_ECHO) += echo/
obj-$(CONFIG_POCH) += poch/
-obj-$(CONFIG_AGNX) += agnx/
obj-$(CONFIG_OTUS) += otus/
obj-$(CONFIG_RT2860) += rt2860/
obj-$(CONFIG_RT2870) += rt2870/
@@ -46,4 +45,3 @@ obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_RAR_REGISTER) += rar/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
-obj-$(CONFIG_COWLOOP) += cowloop/
diff --git a/drivers/staging/agnx/Kconfig b/drivers/staging/agnx/Kconfig
deleted file mode 100644
index 7f43549e36dd..000000000000
--- a/drivers/staging/agnx/Kconfig
+++ /dev/null
@@ -1,5 +0,0 @@
-config AGNX
- tristate "Wireless Airgo AGNX support"
- depends on WLAN_80211 && MAC80211
- ---help---
- This is an experimental driver for Airgo AGNX00 wireless chip.
diff --git a/drivers/staging/agnx/Makefile b/drivers/staging/agnx/Makefile
deleted file mode 100644
index 1216564a312d..000000000000
--- a/drivers/staging/agnx/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-obj-$(CONFIG_AGNX) += agnx.o
-
-agnx-objs := rf.o \
- pci.o \
- xmit.o \
- table.o \
- sta.o \
- phy.o
diff --git a/drivers/staging/agnx/TODO b/drivers/staging/agnx/TODO
deleted file mode 100644
index 89bec74318aa..000000000000
--- a/drivers/staging/agnx/TODO
+++ /dev/null
@@ -1,22 +0,0 @@
-2008 7/18
-
-The RX has can't receive OFDM packet correctly,
-Guess it need be do RX calibrate.
-
-
-before 2008 3/1
-
-1: The RX get too much "CRC failed" pakets, it make the card work very unstable,
-2: After running a while, the card will get infinity "RX Frame" and "Error"
-interrupt, not know the root reason so far, try to fix it
-3: Using two tx queue txd and txm but not only txm.
-4: Set the hdr correctly.
-5: Try to do recalibrate correvtly
-6: To support G mode in future
-7: Fix the mac address can't be readed and set correctly in BE machine.
-8: Fix include and exclude FCS in promisous mode and manage mode
-9: Using sta_notify to notice sta change
-10: Turn on frame reception at the end of start
-11: Guess the card support HW_MULTICAST_FILTER
-12: The tx process should be implment atomic?
-13: Using mac80211 function to control the TX&RX LED.
diff --git a/drivers/staging/agnx/agnx.h b/drivers/staging/agnx/agnx.h
deleted file mode 100644
index 3963d2597a11..000000000000
--- a/drivers/staging/agnx/agnx.h
+++ /dev/null
@@ -1,156 +0,0 @@
-#ifndef AGNX_H_
-#define AGNX_H_
-
-#include <linux/io.h>
-
-#include "xmit.h"
-
-#define PFX KBUILD_MODNAME ": "
-
-static inline u32 agnx_read32(void __iomem *mem_region, u32 offset)
-{
- return ioread32(mem_region + offset);
-}
-
-static inline void agnx_write32(void __iomem *mem_region, u32 offset, u32 val)
-{
- iowrite32(val, mem_region + offset);
-}
-
-/* static const struct ieee80211_rate agnx_rates_80211b[] = { */
-/* { .rate = 10, */
-/* .val = 0xa, */
-/* .flags = IEEE80211_RATE_CCK }, */
-/* { .rate = 20, */
-/* .val = 0x14, */
-/* .hw_value = -0x14, */
-/* .flags = IEEE80211_RATE_CCK_2 }, */
-/* { .rate = 55, */
-/* .val = 0x37, */
-/* .val2 = -0x37, */
-/* .flags = IEEE80211_RATE_CCK_2 }, */
-/* { .rate = 110, */
-/* .val = 0x6e, */
-/* .val2 = -0x6e, */
-/* .flags = IEEE80211_RATE_CCK_2 } */
-/* }; */
-
-
-static const struct ieee80211_rate agnx_rates_80211g[] = {
-/* { .bitrate = 10, .hw_value = 1, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
-/* { .bitrate = 20, .hw_value = 2, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
-/* { .bitrate = 55, .hw_value = 3, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
-/* { .bitrate = 110, .hw_value = 4, .flags = IEEE80211_RATE_SHORT_PREAMBLE }, */
- { .bitrate = 10, .hw_value = 1, },
- { .bitrate = 20, .hw_value = 2, },
- { .bitrate = 55, .hw_value = 3, },
- { .bitrate = 110, .hw_value = 4,},
-
- { .bitrate = 60, .hw_value = 0xB, },
- { .bitrate = 90, .hw_value = 0xF, },
- { .bitrate = 120, .hw_value = 0xA },
- { .bitrate = 180, .hw_value = 0xE, },
-/* { .bitrate = 240, .hw_value = 0xd, }, */
- { .bitrate = 360, .hw_value = 0xD, },
- { .bitrate = 480, .hw_value = 0x8, },
- { .bitrate = 540, .hw_value = 0xC, },
-};
-
-static const struct ieee80211_channel agnx_channels[] = {
- { .center_freq = 2412, .hw_value = 1, },
- { .center_freq = 2417, .hw_value = 2, },
- { .center_freq = 2422, .hw_value = 3, },
- { .center_freq = 2427, .hw_value = 4, },
- { .center_freq = 2432, .hw_value = 5, },
- { .center_freq = 2437, .hw_value = 6, },
- { .center_freq = 2442, .hw_value = 7, },
- { .center_freq = 2447, .hw_value = 8, },
- { .center_freq = 2452, .hw_value = 9, },
- { .center_freq = 2457, .hw_value = 10, },
- { .center_freq = 2462, .hw_value = 11, },
- { .center_freq = 2467, .hw_value = 12, },
- { .center_freq = 2472, .hw_value = 13, },
- { .center_freq = 2484, .hw_value = 14, },
-};
-
-#define NUM_DRIVE_MODES 2
-/* Agnx operate mode */
-enum {
- AGNX_MODE_80211A,
- AGNX_MODE_80211A_OOB,
- AGNX_MODE_80211A_MIMO,
- AGNX_MODE_80211B_SHORT,
- AGNX_MODE_80211B_LONG,
- AGNX_MODE_80211G,
- AGNX_MODE_80211G_OOB,
- AGNX_MODE_80211G_MIMO,
-};
-
-enum {
- AGNX_UNINIT,
- AGNX_START,
- AGNX_STOP,
-};
-
-struct agnx_priv {
- struct pci_dev *pdev;
- struct ieee80211_hw *hw;
-
- spinlock_t lock;
- struct mutex mutex;
- unsigned int init_status;
-
- void __iomem *ctl; /* pointer to base ram address */
- void __iomem *data; /* pointer to mem region #2 */
-
- struct agnx_ring rx;
- struct agnx_ring txm;
- struct agnx_ring txd;
-
- /* Need volatile? */
- u32 irq_status;
-
- struct delayed_work periodic_work; /* Periodic tasks like recalibrate */
- struct ieee80211_low_level_stats stats;
-
- /* unsigned int phymode; */
- int mode;
- int channel;
- u8 bssid[ETH_ALEN];
-
- u8 mac_addr[ETH_ALEN];
- u8 revid;
-
- struct ieee80211_supported_band band;
-};
-
-
-#define AGNX_CHAINS_MAX 6
-#define AGNX_PERIODIC_DELAY 60000 /* unit: ms */
-#define LOCAL_STAID 0 /* the station entry for the card itself */
-#define BSSID_STAID 1 /* the station entry for the bsssid AP */
-#define spi_delay() udelay(40)
-#define eeprom_delay() udelay(40)
-#define routing_table_delay() udelay(50)
-
-/* PDU pool MEM region #2 */
-#define AGNX_PDUPOOL 0x40000 /* PDU pool */
-#define AGNX_PDUPOOL_SIZE 0x8000 /* PDU pool size*/
-#define AGNX_PDU_TX_WQ 0x41000 /* PDU list TX workqueue */
-#define AGNX_PDU_FREE 0x41800 /* Free Pool */
-#define PDU_SIZE 0x80 /* Free Pool node size */
-#define PDU_FREE_CNT 0xd0 /* Free pool node count */
-
-
-/* RF stuffs */
-extern void rf_chips_init(struct agnx_priv *priv);
-extern void spi_rc_write(void __iomem *mem_region, u32 chip_ids, u32 sw);
-extern void calibrate_oscillator(struct agnx_priv *priv);
-extern void do_calibration(struct agnx_priv *priv);
-extern void antenna_calibrate(struct agnx_priv *priv);
-extern void __antenna_calibrate(struct agnx_priv *priv);
-extern void print_offsets(struct agnx_priv *priv);
-extern int agnx_set_channel(struct agnx_priv *priv, unsigned int channel);
-
-
-#endif /* AGNX_H_ */
diff --git a/drivers/staging/agnx/debug.h b/drivers/staging/agnx/debug.h
deleted file mode 100644
index 7947f327a214..000000000000
--- a/drivers/staging/agnx/debug.h
+++ /dev/null
@@ -1,416 +0,0 @@
-#ifndef AGNX_DEBUG_H_
-#define AGNX_DEBUG_H_
-
-#include "agnx.h"
-#include "phy.h"
-#include "sta.h"
-#include "xmit.h"
-
-#define AGNX_TRACE printk(KERN_ERR PFX "function:%s line:%d\n", __func__, __LINE__)
-
-#define PRINTK_LE16(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.4x\n", le16_to_cpu(var))
-#define PRINTK_LE32(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.8x\n", le32_to_cpu(var))
-#define PRINTK_U8(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.2x\n", var)
-#define PRINTK_BE16(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.4x\n", be16_to_cpu(var))
-#define PRINTK_BE32(prefix, var) printk(KERN_DEBUG PFX #prefix ": " #var " 0x%.8x\n", be32_to_cpu(var))
-#define PRINTK_BITS(prefix, field) printk(KERN_DEBUG PFX #prefix ": " #field ": 0x%x\n", (reg & field) >> field##_SHIFT)
-
-static inline void agnx_bug(char *reason)
-{
- printk(KERN_ERR PFX "%s\n", reason);
- BUG();
-}
-
-static inline void agnx_print_desc(struct agnx_desc *desc)
-{
- u32 reg = be32_to_cpu(desc->frag);
-
- PRINTK_BITS(DESC, PACKET_LEN);
-
- if (reg & FIRST_FRAG) {
- PRINTK_BITS(DESC, FIRST_PACKET_MASK);
- PRINTK_BITS(DESC, FIRST_RESERV2);
- PRINTK_BITS(DESC, FIRST_TKIP_ERROR);
- PRINTK_BITS(DESC, FIRST_TKIP_PACKET);
- PRINTK_BITS(DESC, FIRST_RESERV1);
- PRINTK_BITS(DESC, FIRST_FRAG_LEN);
- } else {
- PRINTK_BITS(DESC, SUB_RESERV2);
- PRINTK_BITS(DESC, SUB_TKIP_ERROR);
- PRINTK_BITS(DESC, SUB_TKIP_PACKET);
- PRINTK_BITS(DESC, SUB_RESERV1);
- PRINTK_BITS(DESC, SUB_FRAG_LEN);
- }
-
- PRINTK_BITS(DESC, FIRST_FRAG);
- PRINTK_BITS(DESC, LAST_FRAG);
- PRINTK_BITS(DESC, OWNER);
-}
-
-
-static inline void dump_ieee80211b_phy_hdr(__be32 _11b0, __be32 _11b1)
-{
-
-}
-
-static inline void agnx_print_hdr(struct agnx_hdr *hdr)
-{
- u32 reg;
- int i;
-
- reg = be32_to_cpu(hdr->reg0);
- PRINTK_BITS(HDR, RTS);
- PRINTK_BITS(HDR, MULTICAST);
- PRINTK_BITS(HDR, ACK);
- PRINTK_BITS(HDR, TM);
- PRINTK_BITS(HDR, RELAY);
- PRINTK_BITS(HDR, REVISED_FCS);
- PRINTK_BITS(HDR, NEXT_BUFFER_ADDR);
-
- reg = be32_to_cpu(hdr->reg1);
- PRINTK_BITS(HDR, MAC_HDR_LEN);
- PRINTK_BITS(HDR, DURATION_OVERIDE);
- PRINTK_BITS(HDR, PHY_HDR_OVERIDE);
- PRINTK_BITS(HDR, CRC_FAIL);
- PRINTK_BITS(HDR, SEQUENCE_NUMBER);
- PRINTK_BITS(HDR, BUFF_HEAD_ADDR);
-
- reg = be32_to_cpu(hdr->reg2);
- PRINTK_BITS(HDR, PDU_COUNT);
- PRINTK_BITS(HDR, WEP_KEY);
- PRINTK_BITS(HDR, USES_WEP_KEY);
- PRINTK_BITS(HDR, KEEP_ALIVE);
- PRINTK_BITS(HDR, BUFF_TAIL_ADDR);
-
- reg = be32_to_cpu(hdr->reg3);
- PRINTK_BITS(HDR, CTS_11G);
- PRINTK_BITS(HDR, RTS_11G);
- PRINTK_BITS(HDR, FRAG_SIZE);
- PRINTK_BITS(HDR, PAYLOAD_LEN);
- PRINTK_BITS(HDR, FRAG_NUM);
-
- reg = be32_to_cpu(hdr->reg4);
- PRINTK_BITS(HDR, RELAY_STAID);
- PRINTK_BITS(HDR, STATION_ID);
- PRINTK_BITS(HDR, WORKQUEUE_ID);
-
- reg = be32_to_cpu(hdr->reg5);
- /* printf the route flag */
- PRINTK_BITS(HDR, ROUTE_HOST);
- PRINTK_BITS(HDR, ROUTE_CARD_CPU);
- PRINTK_BITS(HDR, ROUTE_ENCRYPTION);
- PRINTK_BITS(HDR, ROUTE_TX);
- PRINTK_BITS(HDR, ROUTE_RX1);
- PRINTK_BITS(HDR, ROUTE_RX2);
- PRINTK_BITS(HDR, ROUTE_COMPRESSION);
-
- PRINTK_BE32(HDR, hdr->_11g0);
- PRINTK_BE32(HDR, hdr->_11g1);
- PRINTK_BE32(HDR, hdr->_11b0);
- PRINTK_BE32(HDR, hdr->_11b1);
-
- dump_ieee80211b_phy_hdr(hdr->_11b0, hdr->_11b1);
-
- /* Fixme */
- for (i = 0; i < ARRAY_SIZE(hdr->mac_hdr); i++) {
- if (i == 0)
- printk(KERN_DEBUG PFX "IEEE80211 HDR: ");
- printk("%.2x ", hdr->mac_hdr[i]);
- if (i + 1 == ARRAY_SIZE(hdr->mac_hdr))
- printk("\n");
- }
-
- PRINTK_BE16(HDR, hdr->rts_duration);
- PRINTK_BE16(HDR, hdr->last_duration);
- PRINTK_BE16(HDR, hdr->sec_last_duration);
- PRINTK_BE16(HDR, hdr->other_duration);
- PRINTK_BE16(HDR, hdr->tx_other_duration);
- PRINTK_BE16(HDR, hdr->last_11g_len);
- PRINTK_BE16(HDR, hdr->other_11g_len);
- PRINTK_BE16(HDR, hdr->last_11b_len);
- PRINTK_BE16(HDR, hdr->other_11b_len);
-
- /* FIXME */
- reg = be16_to_cpu(hdr->reg6);
- PRINTK_BITS(HDR, MBF);
- PRINTK_BITS(HDR, RSVD4);
-
- PRINTK_BE16(HDR, hdr->rx_frag_stat);
-
- PRINTK_BE32(HDR, hdr->time_stamp);
- PRINTK_BE32(HDR, hdr->phy_stats_hi);
- PRINTK_BE32(HDR, hdr->phy_stats_lo);
- PRINTK_BE32(HDR, hdr->mic_key0);
- PRINTK_BE32(HDR, hdr->mic_key1);
-} /* agnx_print_hdr */
-
-
-static inline void agnx_print_rx_hdr(struct agnx_hdr *hdr)
-{
- agnx_print_hdr(hdr);
-
- PRINTK_BE16(HDR, hdr->rx.rx_packet_duration);
- PRINTK_BE16(HDR, hdr->rx.replay_cnt);
-
- PRINTK_U8(HDR, hdr->rx_channel);
-}
-
-static inline void agnx_print_tx_hdr(struct agnx_hdr *hdr)
-{
- agnx_print_hdr(hdr);
-
- PRINTK_U8(HDR, hdr->tx.long_retry_limit);
- PRINTK_U8(HDR, hdr->tx.short_retry_limit);
- PRINTK_U8(HDR, hdr->tx.long_retry_cnt);
- PRINTK_U8(HDR, hdr->tx.short_retry_cnt);
-
- PRINTK_U8(HDR, hdr->rx_channel);
-}
-
-static inline void
-agnx_print_sta_power(struct agnx_priv *priv, unsigned int sta_idx)
-{
- struct agnx_sta_power power;
- u32 reg;
-
- get_sta_power(priv, &power, sta_idx);
-
- reg = le32_to_cpu(power.reg);
- PRINTK_BITS(STA_POWER, SIGNAL);
- PRINTK_BITS(STA_POWER, RATE);
- PRINTK_BITS(STA_POWER, TIFS);
- PRINTK_BITS(STA_POWER, EDCF);
- PRINTK_BITS(STA_POWER, CHANNEL_BOND);
- PRINTK_BITS(STA_POWER, PHY_MODE);
- PRINTK_BITS(STA_POWER, POWER_LEVEL);
- PRINTK_BITS(STA_POWER, NUM_TRANSMITTERS);
-}
-
-static inline void
-agnx_print_sta_tx_wq(struct agnx_priv *priv, unsigned int sta_idx, unsigned int wq_idx)
-{
- struct agnx_sta_tx_wq tx_wq;
- u32 reg;
-
- get_sta_tx_wq(priv, &tx_wq, sta_idx, wq_idx);
-
- reg = le32_to_cpu(tx_wq.reg0);
- PRINTK_BITS(STA_TX_WQ, TAIL_POINTER);
- PRINTK_BITS(STA_TX_WQ, HEAD_POINTER_LOW);
-
- reg = le32_to_cpu(tx_wq.reg3);
- PRINTK_BITS(STA_TX_WQ, HEAD_POINTER_HIGH);
- PRINTK_BITS(STA_TX_WQ, ACK_POINTER_LOW);
-
- reg = le32_to_cpu(tx_wq.reg1);
- PRINTK_BITS(STA_TX_WQ, ACK_POINTER_HIGH);
- PRINTK_BITS(STA_TX_WQ, HEAD_TIMOUT_TAIL_PACK_CNT);
- PRINTK_BITS(STA_TX_WQ, ACK_TIMOUT_TAIL_PACK_CNT);
-
- reg = le32_to_cpu(tx_wq.reg2);
- PRINTK_BITS(STA_TX_WQ, HEAD_TIMOUT_WIN_LIM_BYTE_CNT);
- PRINTK_BITS(STA_TX_WQ, HEAD_TIMOUT_WIN_LIM_FRAG_CNT);
- PRINTK_BITS(STA_TX_WQ, WORK_QUEUE_ACK_TYPE);
- PRINTK_BITS(STA_TX_WQ, WORK_QUEUE_VALID);
-}
-
-static inline void agnx_print_sta_traffic(struct agnx_sta_traffic *traffic)
-{
- u32 reg;
-
- reg = le32_to_cpu(traffic->reg0);
- PRINTK_BITS(STA_TRAFFIC, ACK_TIMOUT_CNT);
- PRINTK_BITS(STA_TRAFFIC, TRAFFIC_ACK_TYPE);
- PRINTK_BITS(STA_TRAFFIC, NEW_PACKET);
- PRINTK_BITS(STA_TRAFFIC, TRAFFIC_VALID);
- PRINTK_BITS(STA_TRAFFIC, RX_HDR_DESC_POINTER);
-
- reg = le32_to_cpu(traffic->reg1);
- PRINTK_BITS(STA_TRAFFIC, RX_PACKET_TIMESTAMP);
- PRINTK_BITS(STA_TRAFFIC, TRAFFIC_RESERVED);
- PRINTK_BITS(STA_TRAFFIC, SV);
- PRINTK_BITS(STA_TRAFFIC, RX_SEQUENCE_NUM);
-
- PRINTK_LE32(STA_TRAFFIC, traffic->tx_replay_cnt_low);
-
- PRINTK_LE16(STA_TRAFFIC, traffic->tx_replay_cnt_high);
- PRINTK_LE16(STA_TRAFFIC, traffic->rx_replay_cnt_high);
-
- PRINTK_LE32(STA_TRAFFIC, traffic->rx_replay_cnt_low);
-}
-
-static inline void agnx_print_sta(struct agnx_priv *priv, unsigned int sta_idx)
-{
- struct agnx_sta station;
- struct agnx_sta *sta = &station;
- u32 reg;
- unsigned int i;
-
- get_sta(priv, sta, sta_idx);
-
- for (i = 0; i < 4; i++)
- PRINTK_LE32(STA, sta->tx_session_keys[i]);
- for (i = 0; i < 4; i++)
- PRINTK_LE32(STA, sta->rx_session_keys[i]);
-
- reg = le32_to_cpu(sta->reg);
- PRINTK_BITS(STA, ID_1);
- PRINTK_BITS(STA, ID_0);
- PRINTK_BITS(STA, ENABLE_CONCATENATION);
- PRINTK_BITS(STA, ENABLE_DECOMPRESSION);
- PRINTK_BITS(STA, STA_RESERVED);
- PRINTK_BITS(STA, EAP);
- PRINTK_BITS(STA, ED_NULL);
- PRINTK_BITS(STA, ENCRYPTION_POLICY);
- PRINTK_BITS(STA, DEFINED_KEY_ID);
- PRINTK_BITS(STA, FIXED_KEY);
- PRINTK_BITS(STA, KEY_VALID);
- PRINTK_BITS(STA, STATION_VALID);
-
- PRINTK_LE32(STA, sta->tx_aes_blks_unicast);
- PRINTK_LE32(STA, sta->rx_aes_blks_unicast);
-
- PRINTK_LE16(STA, sta->aes_format_err_unicast_cnt);
- PRINTK_LE16(STA, sta->aes_replay_unicast);
-
- PRINTK_LE16(STA, sta->aes_decrypt_err_unicast);
- PRINTK_LE16(STA, sta->aes_decrypt_err_default);
-
- PRINTK_LE16(STA, sta->single_retry_packets);
- PRINTK_LE16(STA, sta->failed_tx_packets);
-
- PRINTK_LE16(STA, sta->muti_retry_packets);
- PRINTK_LE16(STA, sta->ack_timeouts);
-
- PRINTK_LE16(STA, sta->frag_tx_cnt);
- PRINTK_LE16(STA, sta->rts_brq_sent);
-
- PRINTK_LE16(STA, sta->tx_packets);
- PRINTK_LE16(STA, sta->cts_back_timeout);
-
- PRINTK_LE32(STA, sta->phy_stats_high);
- PRINTK_LE32(STA, sta->phy_stats_low);
-
- /* for (i = 0; i < 8; i++) */
- agnx_print_sta_traffic(sta->traffic + 0);
-
- PRINTK_LE16(STA, sta->traffic_class0_frag_success);
- PRINTK_LE16(STA, sta->traffic_class1_frag_success);
- PRINTK_LE16(STA, sta->traffic_class2_frag_success);
- PRINTK_LE16(STA, sta->traffic_class3_frag_success);
- PRINTK_LE16(STA, sta->traffic_class4_frag_success);
- PRINTK_LE16(STA, sta->traffic_class5_frag_success);
- PRINTK_LE16(STA, sta->traffic_class6_frag_success);
- PRINTK_LE16(STA, sta->traffic_class7_frag_success);
-
- PRINTK_LE16(STA, sta->num_frag_non_prime_rates);
- PRINTK_LE16(STA, sta->ack_timeout_non_prime_rates);
-}
-
-
-static inline void dump_ieee80211_hdr(struct ieee80211_hdr *hdr, char *tag)
-{
- u16 fctl;
- int hdrlen;
-
- fctl = le16_to_cpu(hdr->frame_control);
- switch (fctl & IEEE80211_FCTL_FTYPE) {
- case IEEE80211_FTYPE_DATA:
- printk(PFX "%s DATA ", tag);
- break;
- case IEEE80211_FTYPE_CTL:
- printk(PFX "%s CTL ", tag);
- break;
- case IEEE80211_FTYPE_MGMT:
- printk(PFX "%s MGMT ", tag);
- switch (fctl & IEEE80211_FCTL_STYPE) {
- case IEEE80211_STYPE_ASSOC_REQ:
- printk("SubType: ASSOC_REQ ");
- break;
- case IEEE80211_STYPE_ASSOC_RESP:
- printk("SubType: ASSOC_RESP ");
- break;
- case IEEE80211_STYPE_REASSOC_REQ:
- printk("SubType: REASSOC_REQ ");
- break;
- case IEEE80211_STYPE_REASSOC_RESP:
- printk("SubType: REASSOC_RESP ");
- break;
- case IEEE80211_STYPE_PROBE_REQ:
- printk("SubType: PROBE_REQ ");
- break;
- case IEEE80211_STYPE_PROBE_RESP:
- printk("SubType: PROBE_RESP ");
- break;
- case IEEE80211_STYPE_BEACON:
- printk("SubType: BEACON ");
- break;
- case IEEE80211_STYPE_ATIM:
- printk("SubType: ATIM ");
- break;
- case IEEE80211_STYPE_DISASSOC:
- printk("SubType: DISASSOC ");
- break;
- case IEEE80211_STYPE_AUTH:
- printk("SubType: AUTH ");
- break;
- case IEEE80211_STYPE_DEAUTH:
- printk("SubType: DEAUTH ");
- break;
- case IEEE80211_STYPE_ACTION:
- printk("SubType: ACTION ");
- break;
- default:
- printk("SubType: Unknow\n");
- }
- break;
- default:
- printk(PFX "%s Packet type: Unknow\n", tag);
- }
-
- hdrlen = ieee80211_hdrlen(fctl);
-
- if (hdrlen >= 4)
- printk("FC=0x%04x DUR=0x%04x",
- fctl, le16_to_cpu(hdr->duration_id));
- if (hdrlen >= 10)
- printk(" A1=%pM", hdr->addr1);
- if (hdrlen >= 16)
- printk(" A2=%pM", hdr->addr2);
- if (hdrlen >= 24)
- printk(" A3=%pM", hdr->addr3);
- if (hdrlen >= 30)
- printk(" A4=%pM", hdr->addr4);
- printk("\n");
-}
-
-static inline void dump_txm_registers(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- int i;
- for (i = 0; i <= 0x1e8; i += 4)
- printk(KERN_DEBUG PFX "TXM: %x---> 0x%.8x\n", i, ioread32(ctl + i));
-}
-static inline void dump_rxm_registers(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- int i;
- for (i = 0; i <= 0x108; i += 4)
- printk(KERN_DEBUG PFX "RXM: %x---> 0x%.8x\n", i, ioread32(ctl + 0x2000 + i));
-}
-static inline void dump_bm_registers(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- int i;
- for (i = 0; i <= 0x90; i += 4)
- printk(KERN_DEBUG PFX "BM: %x---> 0x%.8x\n", i, ioread32(ctl + 0x2c00 + i));
-}
-static inline void dump_cir_registers(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- int i;
- for (i = 0; i <= 0xb8; i += 4)
- printk(KERN_DEBUG PFX "CIR: %x---> 0x%.8x\n", i, ioread32(ctl + 0x3000 + i));
-}
-
-#endif /* AGNX_DEBUG_H_ */
diff --git a/drivers/staging/agnx/pci.c b/drivers/staging/agnx/pci.c
deleted file mode 100644
index 32b5489456a8..000000000000
--- a/drivers/staging/agnx/pci.c
+++ /dev/null
@@ -1,635 +0,0 @@
-/**
- * Airgo MIMO wireless driver
- *
- * Copyright (c) 2007 Li YanBo <dreamfly281@gmail.com>
-
- * Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer
- * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin
-
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/etherdevice.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-
-#include "agnx.h"
-#include "debug.h"
-#include "xmit.h"
-#include "phy.h"
-
-MODULE_AUTHOR("Li YanBo <dreamfly281@gmail.com>");
-MODULE_DESCRIPTION("Airgo MIMO PCI wireless driver");
-MODULE_LICENSE("GPL");
-
-static struct pci_device_id agnx_pci_id_tbl[] __devinitdata = {
- { PCI_DEVICE(0x17cb, 0x0001) }, /* Beklin F5d8010, Netgear WGM511 etc */
- { PCI_DEVICE(0x17cb, 0x0002) }, /* Netgear Wpnt511 */
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, agnx_pci_id_tbl);
-
-
-static inline void agnx_interrupt_ack(struct agnx_priv *priv, u32 *reason)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
-
- if (*reason & AGNX_STAT_RX) {
- /* Mark complete RX */
- reg = ioread32(ctl + AGNX_CIR_RXCTL);
- reg |= 0x4;
- iowrite32(reg, ctl + AGNX_CIR_RXCTL);
- /* disable Rx interrupt */
- }
- if (*reason & AGNX_STAT_TX) {
- reg = ioread32(ctl + AGNX_CIR_TXDCTL);
- if (reg & 0x4) {
- iowrite32(reg, ctl + AGNX_CIR_TXDCTL);
- *reason |= AGNX_STAT_TXD;
- }
- reg = ioread32(ctl + AGNX_CIR_TXMCTL);
- if (reg & 0x4) {
- iowrite32(reg, ctl + AGNX_CIR_TXMCTL);
- *reason |= AGNX_STAT_TXM;
- }
- }
-#if 0
- if (*reason & AGNX_STAT_X) {
- reg = ioread32(ctl + AGNX_INT_STAT);
- iowrite32(reg, ctl + AGNX_INT_STAT);
- /* FIXME reinit interrupt mask */
- reg = 0xc390bf9 & ~IRQ_TX_BEACON;
- reg &= ~IRQ_TX_DISABLE;
- iowrite32(reg, ctl + AGNX_INT_MASK);
- iowrite32(0x800, ctl + AGNX_CIR_BLKCTL);
- }
-#endif
-} /* agnx_interrupt_ack */
-
-static irqreturn_t agnx_interrupt_handler(int irq, void *dev_id)
-{
- struct ieee80211_hw *dev = dev_id;
- struct agnx_priv *priv = dev->priv;
- void __iomem *ctl = priv->ctl;
- irqreturn_t ret = IRQ_NONE;
- u32 irq_reason;
-
- spin_lock(&priv->lock);
-
-/* printk(KERN_ERR PFX "Get a interrupt %s\n", __func__); */
-
- if (priv->init_status != AGNX_START)
- goto out;
-
- /* FiXME Here has no lock, Is this will lead to race? */
- irq_reason = ioread32(ctl + AGNX_CIR_BLKCTL);
- if (!(irq_reason & 0x7))
- goto out;
-
- ret = IRQ_HANDLED;
- priv->irq_status = ioread32(ctl + AGNX_INT_STAT);
-
-/* printk(PFX "Interrupt reason is 0x%x\n", irq_reason); */
- /* Make sure the txm and txd flags don't conflict with other unknown
- interrupt flag, maybe is not necessary */
- irq_reason &= 0xF;
-
- disable_rx_interrupt(priv);
- /* TODO Make sure the card finished initialized */
- agnx_interrupt_ack(priv, &irq_reason);
-
- if (irq_reason & AGNX_STAT_RX)
- handle_rx_irq(priv);
- if (irq_reason & AGNX_STAT_TXD)
- handle_txd_irq(priv);
- if (irq_reason & AGNX_STAT_TXM)
- handle_txm_irq(priv);
- if (irq_reason & AGNX_STAT_X)
- handle_other_irq(priv);
-
- enable_rx_interrupt(priv);
-out:
- spin_unlock(&priv->lock);
- return ret;
-} /* agnx_interrupt_handler */
-
-
-/* FIXME */
-static int agnx_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
-{
- AGNX_TRACE;
- return _agnx_tx(dev->priv, skb);
-} /* agnx_tx */
-
-
-static int agnx_get_mac_address(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- AGNX_TRACE;
-
- /* Attention! directly read the MAC or other date from EEPROM will
- lead to cardbus(WGM511) lock up when write to PM PLL register */
- reg = agnx_read32(ctl, 0x3544);
- udelay(40);
- reg = agnx_read32(ctl, 0x354c);
- udelay(50);
- /* Get the mac address */
- reg = agnx_read32(ctl, 0x3544);
- udelay(40);
-
- /* HACK */
- reg = cpu_to_le32(reg);
- priv->mac_addr[0] = ((u8 *)&reg)[2];
- priv->mac_addr[1] = ((u8 *)&reg)[3];
- reg = agnx_read32(ctl, 0x3548);
- udelay(50);
- *((u32 *)(priv->mac_addr + 2)) = cpu_to_le32(reg);
-
- if (!is_valid_ether_addr(priv->mac_addr)) {
- printk(KERN_WARNING PFX "read mac %pM\n", priv->mac_addr);
- printk(KERN_WARNING PFX "Invalid hwaddr! Using random hwaddr\n");
- random_ether_addr(priv->mac_addr);
- }
-
- return 0;
-} /* agnx_get_mac_address */
-
-static int agnx_alloc_rings(struct agnx_priv *priv)
-{
- unsigned int len;
- AGNX_TRACE;
-
- /* Allocate RX/TXM/TXD rings info */
- priv->rx.size = AGNX_RX_RING_SIZE;
- priv->txm.size = AGNX_TXM_RING_SIZE;
- priv->txd.size = AGNX_TXD_RING_SIZE;
-
- len = priv->rx.size + priv->txm.size + priv->txd.size;
-
-/* priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_KERNEL); */
- priv->rx.info = kzalloc(sizeof(struct agnx_info) * len, GFP_ATOMIC);
- if (!priv->rx.info)
- return -ENOMEM;
- priv->txm.info = priv->rx.info + priv->rx.size;
- priv->txd.info = priv->txm.info + priv->txm.size;
-
- /* Allocate RX/TXM/TXD descriptors */
- priv->rx.desc = pci_alloc_consistent(priv->pdev, sizeof(struct agnx_desc) * len,
- &priv->rx.dma);
- if (!priv->rx.desc) {
- kfree(priv->rx.info);
- return -ENOMEM;
- }
-
- priv->txm.desc = priv->rx.desc + priv->rx.size;
- priv->txm.dma = priv->rx.dma + sizeof(struct agnx_desc) * priv->rx.size;
- priv->txd.desc = priv->txm.desc + priv->txm.size;
- priv->txd.dma = priv->txm.dma + sizeof(struct agnx_desc) * priv->txm.size;
-
- return 0;
-} /* agnx_alloc_rings */
-
-static void rings_free(struct agnx_priv *priv)
-{
- unsigned int len = priv->rx.size + priv->txm.size + priv->txd.size;
- unsigned long flags;
- AGNX_TRACE;
-
- spin_lock_irqsave(&priv->lock, flags);
- kfree(priv->rx.info);
- pci_free_consistent(priv->pdev, sizeof(struct agnx_desc) * len,
- priv->rx.desc, priv->rx.dma);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-#if 0
-static void agnx_periodic_work_handler(struct work_struct *work)
-{
- struct agnx_priv *priv = container_of(work, struct agnx_priv, periodic_work.work);
-/* unsigned long flags; */
- unsigned long delay;
-
- /* fixme: using mutex?? */
-/* spin_lock_irqsave(&priv->lock, flags); */
-
- /* TODO Recalibrate*/
-/* calibrate_oscillator(priv); */
-/* antenna_calibrate(priv); */
-/* agnx_send_packet(priv, 997); */
- /* FIXME */
-/* if (debug == 3) */
-/* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
-/* else */
- delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY);
-/* delay = round_jiffies(HZ * 15); */
-
- queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay);
-
-/* spin_unlock_irqrestore(&priv->lock, flags); */
-}
-#endif
-
-static int agnx_start(struct ieee80211_hw *dev)
-{
- struct agnx_priv *priv = dev->priv;
- /* unsigned long delay; */
- int err = 0;
- AGNX_TRACE;
-
- err = agnx_alloc_rings(priv);
- if (err) {
- printk(KERN_ERR PFX "Can't alloc RX/TXM/TXD rings\n");
- goto out;
- }
- err = request_irq(priv->pdev->irq, &agnx_interrupt_handler,
- IRQF_SHARED, "agnx_pci", dev);
- if (err) {
- printk(KERN_ERR PFX "Failed to register IRQ handler\n");
- rings_free(priv);
- goto out;
- }
-
-/* mdelay(500); */
-
- might_sleep();
- agnx_hw_init(priv);
-
-/* mdelay(500); */
- might_sleep();
-
- priv->init_status = AGNX_START;
-/* INIT_DELAYED_WORK(&priv->periodic_work, agnx_periodic_work_handler); */
-/* delay = msecs_to_jiffies(AGNX_PERIODIC_DELAY); */
-/* queue_delayed_work(priv->hw->workqueue, &priv->periodic_work, delay); */
-out:
- return err;
-} /* agnx_start */
-
-static void agnx_stop(struct ieee80211_hw *dev)
-{
- struct agnx_priv *priv = dev->priv;
- AGNX_TRACE;
-
- priv->init_status = AGNX_STOP;
- /* make sure hardware will not generate irq */
- agnx_hw_reset(priv);
- free_irq(priv->pdev->irq, dev);
-/* flush_workqueue(priv->hw->workqueue); */
-/* cancel_delayed_work_sync(&priv->periodic_work); */
- unfill_rings(priv);
- rings_free(priv);
-}
-
-static int agnx_config(struct ieee80211_hw *dev, u32 changed)
-{
- struct agnx_priv *priv = dev->priv;
- struct ieee80211_conf *conf = &dev->conf;
- int channel = ieee80211_frequency_to_channel(conf->channel->center_freq);
- AGNX_TRACE;
-
- spin_lock(&priv->lock);
- /* FIXME need priv lock? */
- if (channel != priv->channel) {
- priv->channel = channel;
- agnx_set_channel(priv, priv->channel);
- }
-
- spin_unlock(&priv->lock);
- return 0;
-}
-
-static void agnx_bss_info_changed(struct ieee80211_hw *dev,
- struct ieee80211_vif *vif,
- struct ieee80211_bss_conf *conf,
- u32 changed)
-{
- struct agnx_priv *priv = dev->priv;
- void __iomem *ctl = priv->ctl;
- AGNX_TRACE;
-
- if (!(changed & BSS_CHANGED_BSSID))
- return;
-
- spin_lock(&priv->lock);
-
- if (memcmp(conf->bssid, priv->bssid, ETH_ALEN)) {
- agnx_set_bssid(priv, conf->bssid);
- memcpy(priv->bssid, conf->bssid, ETH_ALEN);
- hash_write(priv, conf->bssid, BSSID_STAID);
- sta_init(priv, BSSID_STAID);
- /* FIXME needed? */
- sta_power_init(priv, BSSID_STAID);
- agnx_write32(ctl, AGNX_BM_MTSM, 0xff & ~0x1);
- }
- spin_unlock(&priv->lock);
-} /* agnx_bss_info_changed */
-
-
-static void agnx_configure_filter(struct ieee80211_hw *dev,
- unsigned int changed_flags,
- unsigned int *total_flags,
- int mc_count, struct dev_mc_list *mclist)
-{
- unsigned int new_flags = 0;
-
- *total_flags = new_flags;
- /* TODO */
-}
-
-static int agnx_add_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
-{
- struct agnx_priv *priv = dev->priv;
- AGNX_TRACE;
-
- spin_lock(&priv->lock);
- /* FIXME */
- if (priv->mode != NL80211_IFTYPE_MONITOR)
- return -EOPNOTSUPP;
-
- switch (conf->type) {
- case NL80211_IFTYPE_STATION:
- priv->mode = conf->type;
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- spin_unlock(&priv->lock);
-
- return 0;
-}
-
-static void agnx_remove_interface(struct ieee80211_hw *dev,
- struct ieee80211_if_init_conf *conf)
-{
- struct agnx_priv *priv = dev->priv;
- AGNX_TRACE;
-
- /* TODO */
- priv->mode = NL80211_IFTYPE_MONITOR;
-}
-
-static int agnx_get_stats(struct ieee80211_hw *dev,
- struct ieee80211_low_level_stats *stats)
-{
- struct agnx_priv *priv = dev->priv;
- AGNX_TRACE;
- spin_lock(&priv->lock);
- /* TODO !! */
- memcpy(stats, &priv->stats, sizeof(*stats));
- spin_unlock(&priv->lock);
-
- return 0;
-}
-
-static u64 agnx_get_tsft(struct ieee80211_hw *dev)
-{
- void __iomem *ctl = ((struct agnx_priv *)dev->priv)->ctl;
- u32 tsftl;
- u64 tsft;
- AGNX_TRACE;
-
- /* FIXME */
- tsftl = ioread32(ctl + AGNX_TXM_TIMESTAMPLO);
- tsft = ioread32(ctl + AGNX_TXM_TIMESTAMPHI);
- tsft <<= 32;
- tsft |= tsftl;
-
- return tsft;
-}
-
-static int agnx_get_tx_stats(struct ieee80211_hw *dev,
- struct ieee80211_tx_queue_stats *stats)
-{
- struct agnx_priv *priv = dev->priv;
- AGNX_TRACE;
-
- /* FIXME now we just using txd queue, but should using txm queue too */
- stats[0].len = (priv->txd.idx - priv->txd.idx_sent) / 2;
- stats[0].limit = priv->txd.size - 2;
- stats[0].count = priv->txd.idx / 2;
-
- return 0;
-}
-
-static struct ieee80211_ops agnx_ops = {
- .tx = agnx_tx,
- .start = agnx_start,
- .stop = agnx_stop,
- .add_interface = agnx_add_interface,
- .remove_interface = agnx_remove_interface,
- .config = agnx_config,
- .bss_info_changed = agnx_bss_info_changed,
- .configure_filter = agnx_configure_filter,
- .get_stats = agnx_get_stats,
- .get_tx_stats = agnx_get_tx_stats,
- .get_tsf = agnx_get_tsft
-};
-
-static void __devexit agnx_pci_remove(struct pci_dev *pdev)
-{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- struct agnx_priv *priv;
- AGNX_TRACE;
-
- if (!dev)
- return;
- priv = dev->priv;
- ieee80211_unregister_hw(dev);
- pci_iounmap(pdev, priv->ctl);
- pci_iounmap(pdev, priv->data);
- pci_release_regions(pdev);
- pci_disable_device(pdev);
-
- ieee80211_free_hw(dev);
-}
-
-static int __devinit agnx_pci_probe(struct pci_dev *pdev,
- const struct pci_device_id *id)
-{
- struct ieee80211_hw *dev;
- struct agnx_priv *priv;
- int err;
-
- err = pci_enable_device(pdev);
- if (err) {
- dev_err(&pdev->dev, "can't enable pci device\n");
- return err;
- }
-
- err = pci_request_regions(pdev, "agnx-pci");
- if (err) {
- dev_err(&pdev->dev, "can't reserve PCI resources\n");
- return err;
- }
-
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) ||
- pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
- dev_err(&pdev->dev, "no suitable DMA available\n");
- err = -EIO;
- goto err_free_reg;
- }
-
- pci_set_master(pdev);
-
- dev = ieee80211_alloc_hw(sizeof(*priv), &agnx_ops);
- if (!dev) {
- dev_err(&pdev->dev, "ieee80211 alloc failed\n");
- err = -ENOMEM;
- goto err_free_reg;
- }
- priv = dev->priv;
- memset(priv, 0, sizeof(*priv));
- priv->mode = NL80211_IFTYPE_MONITOR;
- priv->pdev = pdev;
- priv->hw = dev;
- spin_lock_init(&priv->lock);
- priv->init_status = AGNX_UNINIT;
-
- priv->ctl = pci_iomap(pdev, 0, 0);
-/* dev_dbg(&pdev->dev, "MEM1 mapped address is 0x%p\n", priv->ctl); */
- if (!priv->ctl) {
- dev_err(&pdev->dev, "can't map device memory\n");
- err = -ENOMEM;
- goto err_free_dev;
- }
- priv->data = pci_iomap(pdev, 1, 0);
- if (!priv->data) {
- dev_err(&pdev->dev, "can't map device memory\n");
- err = -ENOMEM;
- goto err_iounmap2;
- }
-
- pci_read_config_byte(pdev, PCI_REVISION_ID, &priv->revid);
-
- priv->band.channels = (struct ieee80211_channel *)agnx_channels;
- priv->band.n_channels = ARRAY_SIZE(agnx_channels);
- priv->band.bitrates = (struct ieee80211_rate *)agnx_rates_80211g;
- priv->band.n_bitrates = ARRAY_SIZE(agnx_rates_80211g);
-
- /* Init ieee802.11 dev */
- SET_IEEE80211_DEV(dev, &pdev->dev);
- pci_set_drvdata(pdev, dev);
- dev->extra_tx_headroom = sizeof(struct agnx_hdr);
-
- /* FIXME It only include FCS in promious mode but not manage mode */
-/* dev->flags = IEEE80211_HW_RX_INCLUDES_FCS; */
- dev->channel_change_time = 5000;
- dev->max_signal = 100;
- /* FIXME */
- dev->queues = 1;
-
- agnx_get_mac_address(priv);
-
- SET_IEEE80211_PERM_ADDR(dev, priv->mac_addr);
-
-/* /\* FIXME *\/ */
-/* for (i = 1; i < NUM_DRIVE_MODES; i++) { */
-/* err = ieee80211_register_hwmode(dev, &priv->modes[i]); */
-/* if (err) { */
-/* printk(KERN_ERR PFX "Can't register hwmode\n"); */
-/* goto err_iounmap; */
-/* } */
-/* } */
-
- priv->channel = 1;
- dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
-
- err = ieee80211_register_hw(dev);
- if (err) {
- dev_err(&pdev->dev, "can't register hardware\n");
- goto err_iounmap;
- }
-
- agnx_hw_reset(priv);
-
- dev_info(&pdev->dev, "%s: hwaddr %pM, Rev 0x%02x\n",
- wiphy_name(dev->wiphy),
- dev->wiphy->perm_addr, priv->revid);
- return 0;
-
- err_iounmap:
- pci_iounmap(pdev, priv->data);
-
- err_iounmap2:
- pci_iounmap(pdev, priv->ctl);
-
- err_free_dev:
- pci_set_drvdata(pdev, NULL);
- ieee80211_free_hw(dev);
-
- err_free_reg:
- pci_release_regions(pdev);
-
- pci_disable_device(pdev);
- return err;
-} /* agnx_pci_probe*/
-
-#ifdef CONFIG_PM
-
-static int agnx_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- AGNX_TRACE;
-
- ieee80211_stop_queues(dev);
- agnx_stop(dev);
-
- pci_save_state(pdev);
- pci_set_power_state(pdev, pci_choose_state(pdev, state));
- return 0;
-}
-
-static int agnx_pci_resume(struct pci_dev *pdev)
-{
- struct ieee80211_hw *dev = pci_get_drvdata(pdev);
- AGNX_TRACE;
-
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
-
- agnx_start(dev);
- ieee80211_wake_queues(dev);
-
- return 0;
-}
-
-#else
-
-#define agnx_pci_suspend NULL
-#define agnx_pci_resume NULL
-
-#endif /* CONFIG_PM */
-
-
-static struct pci_driver agnx_pci_driver = {
- .name = "agnx-pci",
- .id_table = agnx_pci_id_tbl,
- .probe = agnx_pci_probe,
- .remove = __devexit_p(agnx_pci_remove),
- .suspend = agnx_pci_suspend,
- .resume = agnx_pci_resume,
-};
-
-static int __init agnx_pci_init(void)
-{
- AGNX_TRACE;
- return pci_register_driver(&agnx_pci_driver);
-}
-
-static void __exit agnx_pci_exit(void)
-{
- AGNX_TRACE;
- pci_unregister_driver(&agnx_pci_driver);
-}
-
-
-module_init(agnx_pci_init);
-module_exit(agnx_pci_exit);
diff --git a/drivers/staging/agnx/phy.c b/drivers/staging/agnx/phy.c
deleted file mode 100644
index ec1ca86fa0c4..000000000000
--- a/drivers/staging/agnx/phy.c
+++ /dev/null
@@ -1,960 +0,0 @@
-/**
- * Airgo MIMO wireless driver
- *
- * Copyright (c) 2007 Li YanBo <dreamfly281@gmail.com>
-
- * Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer
- * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin
-
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/init.h>
-#include <linux/etherdevice.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include "agnx.h"
-#include "debug.h"
-#include "phy.h"
-#include "table.h"
-#include "sta.h"
-#include "xmit.h"
-
-u8 read_from_eeprom(struct agnx_priv *priv, u16 address)
-{
- void __iomem *ctl = priv->ctl;
- struct agnx_eeprom cmd;
- u32 reg;
-
- memset(&cmd, 0, sizeof(cmd));
- cmd.cmd = EEPROM_CMD_READ << AGNX_EEPROM_COMMAND_SHIFT;
- cmd.address = address;
- /* Verify that the Status bit is clear */
- /* Read Command and Address are written to the Serial Interface */
- iowrite32(*(__le32 *)&cmd, ctl + AGNX_CIR_SERIALITF);
- /* Wait for the Status bit to clear again */
- eeprom_delay();
- /* Read from Data */
- reg = ioread32(ctl + AGNX_CIR_SERIALITF);
-
- cmd = *(struct agnx_eeprom *)&reg;
-
- return cmd.data;
-}
-
-static int card_full_reset(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- AGNX_TRACE;
-
- reg = agnx_read32(ctl, AGNX_CIR_BLKCTL);
- agnx_write32(ctl, AGNX_CIR_BLKCTL, 0x80);
- reg = agnx_read32(ctl, AGNX_CIR_BLKCTL);
- return 0;
-}
-
-inline void enable_power_saving(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
-
- reg = agnx_read32(ctl, AGNX_PM_PMCTL);
- reg &= ~0x8;
- agnx_write32(ctl, AGNX_PM_PMCTL, reg);
-}
-
-inline void disable_power_saving(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
-
- reg = agnx_read32(ctl, AGNX_PM_PMCTL);
- reg |= 0x8;
- agnx_write32(ctl, AGNX_PM_PMCTL, reg);
-}
-
-
-void disable_receiver(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- AGNX_TRACE;
-
- /* FIXME Disable the receiver */
- agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x0);
- /* Set gain control reset */
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
- /* Reset gain control reset */
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);
-}
-
-
-/* Fixme this shoule be disable RX, above is enable RX */
-void enable_receiver(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- AGNX_TRACE;
-
- /* Set adaptive gain control discovery mode */
- agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
- /* Set gain control reset */
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
- /* Clear gain control reset */
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);
-}
-
-static void mac_address_set(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u8 *mac_addr = priv->mac_addr;
- u32 reg;
-
- /* FIXME */
- reg = (mac_addr[0] << 24) | (mac_addr[1] << 16) | mac_addr[2] << 8 | mac_addr[3];
- iowrite32(reg, ctl + AGNX_RXM_MACHI);
- reg = (mac_addr[4] << 8) | mac_addr[5];
- iowrite32(reg, ctl + AGNX_RXM_MACLO);
-}
-
-static void receiver_bssid_set(struct agnx_priv *priv, const u8 *bssid)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
-
- disable_receiver(priv);
- /* FIXME */
- reg = bssid[0] << 24 | (bssid[1] << 16) | (bssid[2] << 8) | bssid[3];
- iowrite32(reg, ctl + AGNX_RXM_BSSIDHI);
- reg = (bssid[4] << 8) | bssid[5];
- iowrite32(reg, ctl + AGNX_RXM_BSSIDLO);
-
- /* Enable the receiver */
- enable_receiver(priv);
-
- /* Clear the TSF */
-/* agnx_write32(ctl, AGNX_TXM_TSFLO, 0x0); */
-/* agnx_write32(ctl, AGNX_TXM_TSFHI, 0x0); */
- /* Clear the TBTT */
- agnx_write32(ctl, AGNX_TXM_TBTTLO, 0x0);
- agnx_write32(ctl, AGNX_TXM_TBTTHI, 0x0);
- disable_receiver(priv);
-} /* receiver_bssid_set */
-
-static void band_management_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- void __iomem *data = priv->data;
- u32 reg;
- int i;
- AGNX_TRACE;
-
- agnx_write32(ctl, AGNX_BM_TXWADDR, AGNX_PDU_TX_WQ);
- agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x0);
- memset_io(data + AGNX_PDUPOOL, 0x0, AGNX_PDUPOOL_SIZE);
- agnx_write32(ctl, AGNX_BM_BMCTL, 0x200);
-
- agnx_write32(ctl, AGNX_BM_CIPDUWCNT, 0x40);
- agnx_write32(ctl, AGNX_BM_SPPDUWCNT, 0x2);
- agnx_write32(ctl, AGNX_BM_RFPPDUWCNT, 0x0);
- agnx_write32(ctl, AGNX_BM_RHPPDUWCNT, 0x22);
-
- /* FIXME Initialize the Free Pool Linked List */
- /* 1. Write the Address of the Next Node ((0x41800 + node*size)/size)
- to the first word of each node. */
- for (i = 0; i < PDU_FREE_CNT; i++) {
- iowrite32((AGNX_PDU_FREE + (i+1)*PDU_SIZE)/PDU_SIZE,
- data + AGNX_PDU_FREE + (PDU_SIZE * i));
- /* The last node should be set to 0x0 */
- if ((i + 1) == PDU_FREE_CNT)
- memset_io(data + AGNX_PDU_FREE + (PDU_SIZE * i),
- 0x0, PDU_SIZE);
- }
-
- /* Head is First Pool address (0x41800) / size (0x80) */
- agnx_write32(ctl, AGNX_BM_FPLHP, AGNX_PDU_FREE/PDU_SIZE);
- /* Tail is Last Pool Address (0x47f80) / size (0x80) */
- agnx_write32(ctl, AGNX_BM_FPLTP, 0x47f80/PDU_SIZE);
- /* Count is Number of Nodes in the Pool (0xd0) */
- agnx_write32(ctl, AGNX_BM_FPCNT, PDU_FREE_CNT);
-
- /* Start all workqueue */
- agnx_write32(ctl, AGNX_BM_CIWQCTL, 0x80000);
- agnx_write32(ctl, AGNX_BM_CPULWCTL, 0x80000);
- agnx_write32(ctl, AGNX_BM_CPUHWCTL, 0x80000);
- agnx_write32(ctl, AGNX_BM_CPUTXWCTL, 0x80000);
- agnx_write32(ctl, AGNX_BM_CPURXWCTL, 0x80000);
- agnx_write32(ctl, AGNX_BM_SPRXWCTL, 0x80000);
- agnx_write32(ctl, AGNX_BM_SPTXWCTL, 0x80000);
- agnx_write32(ctl, AGNX_BM_RFPWCTL, 0x80000);
-
- /* Enable the Band Management */
- reg = agnx_read32(ctl, AGNX_BM_BMCTL);
- reg |= 0x1;
- agnx_write32(ctl, AGNX_BM_BMCTL, reg);
-} /* band_managment_init */
-
-
-static void system_itf_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- AGNX_TRACE;
-
- agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x0);
- agnx_write32(ctl, AGNX_PM_TESTPHY, 0x11e143a);
-
- if (priv->revid == 0) {
- reg = agnx_read32(ctl, AGNX_SYSITF_SYSMODE);
- reg |= 0x11;
- agnx_write32(ctl, AGNX_SYSITF_SYSMODE, reg);
- }
- /* ??? What is that means? it should difference for differice type
- of cards */
- agnx_write32(ctl, AGNX_CIR_SERIALITF, 0xfff81006);
-
- agnx_write32(ctl, AGNX_SYSITF_GPIOIN, 0x1f0000);
- agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x5);
- reg = agnx_read32(ctl, AGNX_SYSITF_GPIOIN);
-}
-
-static void encryption_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- AGNX_TRACE;
-
- agnx_write32(ctl, AGNX_ENCRY_WEPKEY0, 0x0);
- agnx_write32(ctl, AGNX_ENCRY_WEPKEY1, 0x0);
- agnx_write32(ctl, AGNX_ENCRY_WEPKEY2, 0x0);
- agnx_write32(ctl, AGNX_ENCRY_WEPKEY3, 0x0);
- agnx_write32(ctl, AGNX_ENCRY_CCMRECTL, 0x8);
-}
-
-static void tx_management_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- void __iomem *data = priv->data;
- u32 reg;
- AGNX_TRACE;
-
- /* Fill out the ComputationalEngineLookupTable
- * starting at memory #2 offset 0x800
- */
- tx_engine_lookup_tbl_init(priv);
- memset_io(data + 0x1000, 0, 0xfe0);
- /* Enable Transmission Management Functions */
- agnx_write32(ctl, AGNX_TXM_ETMF, 0x3ff);
- /* Write 0x3f to Transmission Template */
- agnx_write32(ctl, AGNX_TXM_TXTEMP, 0x3f);
-
- if (priv->revid >= 2)
- agnx_write32(ctl, AGNX_TXM_SIFSPIFS, 0x1e140a0b);
- else
- agnx_write32(ctl, AGNX_TXM_SIFSPIFS, 0x1e190a0b);
-
- reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS);
- reg &= 0xff00;
- reg |= 0xb;
- agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg);
- reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS);
- reg &= 0xffff00ff;
- reg |= 0xa00;
- agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg);
- /* Enable TIFS */
- agnx_write32(ctl, AGNX_TXM_CTL, 0x40000);
-
- reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS);
- reg &= 0xff00ffff;
- reg |= 0x510000;
- agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg);
- reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY);
- reg &= 0xff00ffff;
- agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg);
- reg = agnx_read32(ctl, AGNX_TXM_TIFSEIFS);
- reg &= 0x00ffffff;
- reg |= 0x1c000000;
- agnx_write32(ctl, AGNX_TXM_TIFSEIFS, reg);
- reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY);
- reg &= 0x00ffffff;
- reg |= 0x01000000;
- agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg);
-
- /* # Set DIF 0-1,2-3,4-5,6-7 to defaults */
- agnx_write32(ctl, AGNX_TXM_DIF01, 0x321d321d);
- agnx_write32(ctl, AGNX_TXM_DIF23, 0x321d321d);
- agnx_write32(ctl, AGNX_TXM_DIF45, 0x321d321d);
- agnx_write32(ctl, AGNX_TXM_DIF67, 0x321d321d);
-
- /* Max Ack timeout limit */
- agnx_write32(ctl, AGNX_TXM_MAXACKTIM, 0x1e19);
- /* Max RX Data Timeout count, */
- reg = agnx_read32(ctl, AGNX_TXM_MAXRXTIME);
- reg &= 0xffff0000;
- reg |= 0xff;
- agnx_write32(ctl, AGNX_TXM_MAXRXTIME, reg);
-
- /* CF poll RX Timeout count */
- reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM);
- reg &= 0xffff;
- reg |= 0xff0000;
- agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg);
-
- /* Max Timeout Exceeded count, */
- reg = agnx_read32(ctl, AGNX_TXM_MAXTIMOUT);
- reg &= 0xff00ffff;
- reg |= 0x190000;
- agnx_write32(ctl, AGNX_TXM_MAXTIMOUT, reg);
-
- /* CF ack timeout limit for 11b */
- reg = agnx_read32(ctl, AGNX_TXM_CFACKT11B);
- reg &= 0xff00;
- reg |= 0x1e;
- agnx_write32(ctl, AGNX_TXM_CFACKT11B, reg);
-
- /* Max CF Poll Timeout Count */
- reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM);
- reg &= 0xffff0000;
- reg |= 0x19;
- agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg);
- /* CF Poll RX Timeout Count */
- reg = agnx_read32(ctl, AGNX_TXM_CFPOLLRXTIM);
- reg &= 0xffff0000;
- reg |= 0x1e;
- agnx_write32(ctl, AGNX_TXM_CFPOLLRXTIM, reg);
-
- /* # write default to */
- /* 1. Schedule Empty Count */
- agnx_write32(ctl, AGNX_TXM_SCHEMPCNT, 0x5);
- /* 2. CFP Period Count */
- agnx_write32(ctl, AGNX_TXM_CFPERCNT, 0x1);
- /* 3. CFP MDV */
- agnx_write32(ctl, AGNX_TXM_CFPMDV, 0x10000);
-
- /* Probe Delay */
- reg = agnx_read32(ctl, AGNX_TXM_PROBDELAY);
- reg &= 0xffff0000;
- reg |= 0x400;
- agnx_write32(ctl, AGNX_TXM_PROBDELAY, reg);
-
- /* Max CCA count Slot */
- reg = agnx_read32(ctl, AGNX_TXM_MAXCCACNTSLOT);
- reg &= 0xffff00ff;
- reg |= 0x900;
- agnx_write32(ctl, AGNX_TXM_MAXCCACNTSLOT, reg);
-
- /* Slot limit/1 msec Limit */
- reg = agnx_read32(ctl, AGNX_TXM_SLOTLIMIT);
- reg &= 0xff00ffff;
- reg |= 0x140077;
- agnx_write32(ctl, AGNX_TXM_SLOTLIMIT, reg);
-
- /* # Set CW #(0-7) to default */
- agnx_write32(ctl, AGNX_TXM_CW0, 0xff0007);
- agnx_write32(ctl, AGNX_TXM_CW1, 0xff0007);
- agnx_write32(ctl, AGNX_TXM_CW2, 0xff0007);
- agnx_write32(ctl, AGNX_TXM_CW3, 0xff0007);
- agnx_write32(ctl, AGNX_TXM_CW4, 0xff0007);
- agnx_write32(ctl, AGNX_TXM_CW5, 0xff0007);
- agnx_write32(ctl, AGNX_TXM_CW6, 0xff0007);
- agnx_write32(ctl, AGNX_TXM_CW7, 0xff0007);
-
- /* # Set Short/Long limit #(0-7) to default */
- agnx_write32(ctl, AGNX_TXM_SLBEALIM0, 0xa000a);
- agnx_write32(ctl, AGNX_TXM_SLBEALIM1, 0xa000a);
- agnx_write32(ctl, AGNX_TXM_SLBEALIM2, 0xa000a);
- agnx_write32(ctl, AGNX_TXM_SLBEALIM3, 0xa000a);
- agnx_write32(ctl, AGNX_TXM_SLBEALIM4, 0xa000a);
- agnx_write32(ctl, AGNX_TXM_SLBEALIM5, 0xa000a);
- agnx_write32(ctl, AGNX_TXM_SLBEALIM6, 0xa000a);
- agnx_write32(ctl, AGNX_TXM_SLBEALIM7, 0xa000a);
-
- reg = agnx_read32(ctl, AGNX_TXM_CTL);
- reg |= 0x1400;
- agnx_write32(ctl, AGNX_TXM_CTL, reg);
- /* Wait for bit 0 in Control Reg to clear */
- udelay(80);
- reg = agnx_read32(ctl, AGNX_TXM_CTL);
- /* Or 0x18000 to Control reg */
- reg = agnx_read32(ctl, AGNX_TXM_CTL);
- reg |= 0x18000;
- agnx_write32(ctl, AGNX_TXM_CTL, reg);
- /* Wait for bit 0 in Control Reg to clear */
- udelay(80);
- reg = agnx_read32(ctl, AGNX_TXM_CTL);
-
- /* Set Listen Interval Count to default */
- agnx_write32(ctl, AGNX_TXM_LISINTERCNT, 0x1);
- /* Set DTIM period count to default */
- agnx_write32(ctl, AGNX_TXM_DTIMPERICNT, 0x2000);
-} /* tx_management_init */
-
-static void rx_management_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- AGNX_TRACE;
-
- /* Initialize the Routing Table */
- routing_table_init(priv);
-
- if (priv->revid >= 3) {
- agnx_write32(ctl, 0x2074, 0x1f171710);
- agnx_write32(ctl, 0x2078, 0x10100d0d);
- agnx_write32(ctl, 0x207c, 0x11111010);
- } else {
- agnx_write32(ctl, AGNX_RXM_DELAY11, 0x0);
- }
- agnx_write32(ctl, AGNX_RXM_REQRATE, 0x8195e00);
-}
-
-
-static void agnx_timer_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- AGNX_TRACE;
-
-/* /\* Write 0x249f00 (tick duration?) to Timer 1 *\/ */
-/* agnx_write32(ctl, AGNX_TIMCTL_TIMER1, 0x249f00); */
-/* /\* Write 0xe2 to Timer 1 Control *\/ */
-/* agnx_write32(ctl, AGNX_TIMCTL_TIM1CTL, 0xe2); */
-
- /* Write 0x249f00 (tick duration?) to Timer 1 */
- agnx_write32(ctl, AGNX_TIMCTL_TIMER1, 0x0);
- /* Write 0xe2 to Timer 1 Control */
- agnx_write32(ctl, AGNX_TIMCTL_TIM1CTL, 0x0);
-
- iowrite32(0xFFFFFFFF, priv->ctl + AGNX_TXM_BEACON_CTL);
-}
-
-static void power_manage_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- AGNX_TRACE;
-
- agnx_write32(ctl, AGNX_PM_MACMSW, 0x1f);
- agnx_write32(ctl, AGNX_PM_RFCTL, 0x1f);
-
- reg = agnx_read32(ctl, AGNX_PM_PMCTL);
- reg &= 0xf00f;
- reg |= 0xa0;
- agnx_write32(ctl, AGNX_PM_PMCTL, reg);
-
- if (priv->revid >= 3) {
- reg = agnx_read32(ctl, AGNX_PM_SOFTRST);
- reg |= 0x18;
- agnx_write32(ctl, AGNX_PM_SOFTRST, reg);
- }
-} /* power_manage_init */
-
-
-static void gain_ctlcnt_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- AGNX_TRACE;
-
- agnx_write32(ctl, AGNX_GCR_TRACNT5, 0x119);
- agnx_write32(ctl, AGNX_GCR_TRACNT6, 0x118);
- agnx_write32(ctl, AGNX_GCR_TRACNT7, 0x117);
-
- reg = agnx_read32(ctl, AGNX_PM_PMCTL);
- reg |= 0x8;
- agnx_write32(ctl, AGNX_PM_PMCTL, reg);
-
- reg = agnx_read32(ctl, AGNX_PM_PMCTL);
- reg &= ~0x8;
- agnx_write32(ctl, AGNX_PM_PMCTL, reg);
-
- agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x0);
-
- /* FIXME Write the initial Station Descriptor for the card */
- sta_init(priv, LOCAL_STAID);
- sta_init(priv, BSSID_STAID);
-
- /* Enable staion 0 and 1 can do TX */
- /* It seemed if we set other bit to 1 the bit 0 will
- be auto change to 0 */
- agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x2 | 0x1);
-/* agnx_write32(ctl, AGNX_BM_TXTOPEER, 0x1); */
-} /* gain_ctlcnt_init */
-
-
-static void phy_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- void __iomem *data = priv->data;
- u32 reg;
- AGNX_TRACE;
-
- /* Load InitialGainTable */
- gain_table_init(priv);
-
- agnx_write32(ctl, AGNX_CIR_ADDRWIN, 0x2000000);
-
- /* Clear the following offsets in Memory Range #2: */
- memset_io(data + 0x5040, 0, 0xa * 4);
- memset_io(data + 0x5080, 0, 0xa * 4);
- memset_io(data + 0x50c0, 0, 0xa * 4);
- memset_io(data + 0x5400, 0, 0x80 * 4);
- memset_io(data + 0x6000, 0, 0x280 * 4);
- memset_io(data + 0x7000, 0, 0x280 * 4);
- memset_io(data + 0x8000, 0, 0x280 * 4);
-
- /* Initialize the Following Registers According to PCI Revision ID */
- if (priv->revid == 0) {
- /* fixme the part hasn't been update but below has been update
- based on WGM511 */
- agnx_write32(ctl, AGNX_ACI_LEN, 0xf);
- agnx_write32(ctl, AGNX_ACI_TIMER1, 0x1d);
- agnx_write32(ctl, AGNX_ACI_TIMER2, 0x3);
- agnx_write32(ctl, AGNX_ACI_AICCHA0OVE, 0x11);
- agnx_write32(ctl, AGNX_ACI_AICCHA1OVE, 0x0);
- agnx_write32(ctl, AGNX_GCR_THD0A, 0x64);
- agnx_write32(ctl, AGNX_GCR_THD0AL, 0x4b);
- agnx_write32(ctl, AGNX_GCR_THD0B, 0x4b);
- agnx_write32(ctl, AGNX_GCR_DUNSAT, 0x14);
- agnx_write32(ctl, AGNX_GCR_DSAT, 0x24);
- agnx_write32(ctl, AGNX_GCR_DFIRCAL, 0x8);
- agnx_write32(ctl, AGNX_GCR_DGCTL11A, 0x1a);
- agnx_write32(ctl, AGNX_GCR_DGCTL11B, 0x3);
- agnx_write32(ctl, AGNX_GCR_GAININIT, 0xd);
- agnx_write32(ctl, AGNX_GCR_THNOSIG, 0x1);
- agnx_write32(ctl, AGNX_GCR_COARSTEP, 0x7);
- agnx_write32(ctl, AGNX_GCR_SIFST11A, 0x28);
- agnx_write32(ctl, AGNX_GCR_SIFST11B, 0x28);
- reg = agnx_read32(ctl, AGNX_GCR_CWDETEC);
- reg |= 0x1;
- agnx_write32(ctl, AGNX_GCR_CWDETEC, reg);
- agnx_write32(ctl, AGNX_GCR_0X38, 0x1e);
- agnx_write32(ctl, AGNX_GCR_BOACT, 0x26);
- agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
- agnx_write32(ctl, AGNX_GCR_NLISTANT, 0x3);
- agnx_write32(ctl, AGNX_GCR_NACTIANT, 0x3);
- agnx_write32(ctl, AGNX_GCR_NMEASANT, 0x3);
- agnx_write32(ctl, AGNX_GCR_NCAPTANT, 0x3);
- agnx_write32(ctl, AGNX_GCR_THCAP11A, 0x0);
- agnx_write32(ctl, AGNX_GCR_THCAP11B, 0x0);
- agnx_write32(ctl, AGNX_GCR_THCAPRX11A, 0x0);
- agnx_write32(ctl, AGNX_GCR_THCAPRX11B, 0x0);
- agnx_write32(ctl, AGNX_GCR_THLEVDRO, 0x10);
- agnx_write32(ctl, AGNX_GCR_MAXRXTIME11A, 0x1);
- agnx_write32(ctl, AGNX_GCR_MAXRXTIME11B, 0x1);
- agnx_write32(ctl, AGNX_GCR_CORRTIME, 0x190);
- agnx_write32(ctl, AGNX_GCR_SIGHTH, 0x78);
- agnx_write32(ctl, AGNX_GCR_SIGLTH, 0x1c);
- agnx_write32(ctl, AGNX_GCR_CORRDROP, 0x0);
- agnx_write32(ctl, AGNX_GCR_THCD, 0x0);
- agnx_write32(ctl, AGNX_GCR_MAXPOWDIFF, 0x1);
- agnx_write32(ctl, AGNX_GCR_TESTBUS, 0x0);
- agnx_write32(ctl, AGNX_GCR_ANTCFG, 0x1f);
- agnx_write32(ctl, AGNX_GCR_THJUMP, 0x14);
- agnx_write32(ctl, AGNX_GCR_THPOWER, 0x0);
- agnx_write32(ctl, AGNX_GCR_THPOWCLIP, 0x30);
- agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 0x32);
- agnx_write32(ctl, AGNX_GCR_THRX11BPOWMIN, 0x19);
- agnx_write32(ctl, AGNX_GCR_0X14c, 0x0);
- agnx_write32(ctl, AGNX_GCR_0X150, 0x0);
- agnx_write32(ctl, 0x9400, 0x0);
- agnx_write32(ctl, 0x940c, 0x6ff);
- agnx_write32(ctl, 0x9428, 0xa0);
- agnx_write32(ctl, 0x9434, 0x0);
- agnx_write32(ctl, 0x9c04, 0x15);
- agnx_write32(ctl, 0x9c0c, 0x7f);
- agnx_write32(ctl, 0x9c34, 0x0);
- agnx_write32(ctl, 0xc000, 0x38d);
- agnx_write32(ctl, 0x14018, 0x0);
- agnx_write32(ctl, 0x16000, 0x1);
- agnx_write32(ctl, 0x11004, 0x0);
- agnx_write32(ctl, 0xec54, 0xa);
- agnx_write32(ctl, 0xec1c, 0x5);
- } else if (priv->revid > 0) {
- agnx_write32(ctl, AGNX_ACI_LEN, 0xf);
- agnx_write32(ctl, AGNX_ACI_TIMER1, 0x21);
- agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
- agnx_write32(ctl, AGNX_ACI_AICCHA0OVE, 0x11);
- agnx_write32(ctl, AGNX_ACI_AICCHA1OVE, 0x0);
- agnx_write32(ctl, AGNX_GCR_DUNSAT, 0x14);
- agnx_write32(ctl, AGNX_GCR_DSAT, 0x24);
- agnx_write32(ctl, AGNX_GCR_DFIRCAL, 0x8);
- agnx_write32(ctl, AGNX_GCR_DGCTL11A, 0x1a);
- agnx_write32(ctl, AGNX_GCR_DGCTL11B, 0x3);
- agnx_write32(ctl, AGNX_GCR_GAININIT, 0xd);
- agnx_write32(ctl, AGNX_GCR_THNOSIG, 0x1);
- agnx_write32(ctl, AGNX_GCR_COARSTEP, 0x7);
- agnx_write32(ctl, AGNX_GCR_SIFST11A, 0x28);
- agnx_write32(ctl, AGNX_GCR_SIFST11B, 0x28);
- agnx_write32(ctl, AGNX_GCR_CWDETEC, 0x0);
- agnx_write32(ctl, AGNX_GCR_0X38, 0x1e);
-/* agnx_write32(ctl, AGNX_GCR_BOACT, 0x26);*/
- agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
-
- agnx_write32(ctl, AGNX_GCR_THCAP11A, 0x32);
- agnx_write32(ctl, AGNX_GCR_THCAP11B, 0x32);
- agnx_write32(ctl, AGNX_GCR_THCAPRX11A, 0x32);
- agnx_write32(ctl, AGNX_GCR_THCAPRX11B, 0x32);
- agnx_write32(ctl, AGNX_GCR_THLEVDRO, 0x10);
- agnx_write32(ctl, AGNX_GCR_MAXRXTIME11A, 0x1ad);
- agnx_write32(ctl, AGNX_GCR_MAXRXTIME11B, 0xa10);
- agnx_write32(ctl, AGNX_GCR_CORRTIME, 0x190);
- agnx_write32(ctl, AGNX_GCR_CORRDROP, 0x0);
- agnx_write32(ctl, AGNX_GCR_THCD, 0x0);
- agnx_write32(ctl, AGNX_GCR_THCS, 0x0);
- agnx_write32(ctl, AGNX_GCR_MAXPOWDIFF, 0x4);
- agnx_write32(ctl, AGNX_GCR_TESTBUS, 0x0);
- agnx_write32(ctl, AGNX_GCR_THJUMP, 0x1e);
- agnx_write32(ctl, AGNX_GCR_THPOWER, 0x0);
- agnx_write32(ctl, AGNX_GCR_THPOWCLIP, 0x2a);
- agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 0x3c);
- agnx_write32(ctl, AGNX_GCR_THRX11BPOWMIN, 0x19);
- agnx_write32(ctl, AGNX_GCR_0X14c, 0x0);
- agnx_write32(ctl, AGNX_GCR_0X150, 0x0);
- agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
- agnx_write32(ctl, AGNX_GCR_WATCHDOG, 0x37);
- agnx_write32(ctl, 0x9400, 0x0);
- agnx_write32(ctl, 0x940c, 0x6ff);
- agnx_write32(ctl, 0x9428, 0xa0);
- agnx_write32(ctl, 0x9434, 0x0);
- agnx_write32(ctl, 0x9c04, 0x15);
- agnx_write32(ctl, 0x9c0c, 0x7f);
- agnx_write32(ctl, 0x9c34, 0x0);
- agnx_write32(ctl, 0xc000, 0x38d);
- agnx_write32(ctl, 0x14014, 0x1000);
- agnx_write32(ctl, 0x14018, 0x0);
- agnx_write32(ctl, 0x16000, 0x1);
- agnx_write32(ctl, 0x11004, 0x0);
- agnx_write32(ctl, 0xec54, 0xa);
- agnx_write32(ctl, 0xec1c, 0x50);
- } else if (priv->revid > 1) {
- reg = agnx_read32(ctl, 0xec18);
- reg |= 0x8;
- agnx_write32(ctl, 0xec18, reg);
- }
-
- /* Write the TX Fir Coefficient Table */
- tx_fir_table_init(priv);
-
- reg = agnx_read32(ctl, AGNX_PM_PMCTL);
- reg &= ~0x8;
- agnx_write32(ctl, AGNX_PM_PMCTL, reg);
- reg = agnx_read32(ctl, AGNX_PM_PLLCTL);
- reg |= 0x1;
- agnx_write32(ctl, AGNX_PM_PLLCTL, reg);
-
-/* reg = agnx_read32(ctl, 0x1a030); */
-/* reg &= ~0x4; */
-/* agnx_write32(ctl, 0x1a030, reg); */
-
- agnx_write32(ctl, AGNX_GCR_TRACNT4, 0x113);
-} /* phy_init */
-
-static void chip_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- AGNX_TRACE;
-
- band_management_init(priv);
-
- rf_chips_init(priv);
-
- reg = agnx_read32(ctl, AGNX_PM_PMCTL);
- reg |= 0x8;
- agnx_write32(ctl, AGNX_PM_PMCTL, reg);
-
- /* Initialize the PHY */
- phy_init(priv);
-
- encryption_init(priv);
-
- tx_management_init(priv);
-
- rx_management_init(priv);
-
- power_manage_init(priv);
-
- /* Initialize the Timers */
- agnx_timer_init(priv);
-
- /* Write 0xc390bf9 to Interrupt Mask (Disable TX) */
- reg = 0xc390bf9 & ~IRQ_TX_BEACON;
- reg &= ~IRQ_TX_DISABLE;
- agnx_write32(ctl, AGNX_INT_MASK, reg);
-
- reg = agnx_read32(ctl, AGNX_CIR_BLKCTL);
- reg |= 0x800;
- agnx_write32(ctl, AGNX_CIR_BLKCTL, reg);
-
- /* set it when need get multicast enable? */
- agnx_write32(ctl, AGNX_BM_MTSM, 0xff);
-} /* chip_init */
-
-
-static inline void set_promis_and_managed(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x10 | 0x2);
- agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x10 | 0x2);
-}
-static inline void set_learn_mode(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x8);
-}
-static inline void set_scan_mode(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x20);
-}
-static inline void set_promiscuous_mode(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- /* agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x210);*/
- agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x10);
-}
-static inline void set_managed_mode(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x2);
-}
-static inline void set_adhoc_mode(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- agnx_write32(ctl, AGNX_SYSITF_SYSMODE, 0x0);
-}
-
-#if 0
-static void unknow_register_write(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
-
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x0, 0x3e);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x4, 0xb2);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x8, 0x140);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0xc, 0x1C0);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x10, 0x1FF);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x14, 0x1DD);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x18, 0x15F);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x1c, 0xA1);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x20, 0x3E7);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x24, 0x36B);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x28, 0x348);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x2c, 0x37D);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x30, 0x3DE);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x34, 0x36);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x38, 0x64);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x3c, 0x57);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x40, 0x23);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x44, 0x3ED);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x48, 0x3C9);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x4c, 0x3CA);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x50, 0x3E7);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x54, 0x8);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x58, 0x1F);
- agnx_write32(ctl, AGNX_UNKNOWN_BASE + 0x5c, 0x1a);
-}
-#endif
-
-static void card_interface_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u8 bssid[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
- u32 reg;
- unsigned int i;
- AGNX_TRACE;
-
- might_sleep();
- /* Clear RX Control and Enable RX queues */
- agnx_write32(ctl, AGNX_CIR_RXCTL, 0x8);
-
- might_sleep();
- /* Do a full reset of the card */
- card_full_reset(priv);
- might_sleep();
-
- /* Check and set Card Endianness */
- reg = ioread32(priv->ctl + AGNX_CIR_ENDIAN);
- /* TODO If not 0xB3B2B1B0 set to 0xB3B2B1B0 */
- printk(KERN_INFO PFX "CIR_ENDIAN is %x\n", reg);
-
-
- /* Config the eeprom */
- agnx_write32(ctl, AGNX_CIR_SERIALITF, 0x7000086);
- udelay(10);
- reg = agnx_read32(ctl, AGNX_CIR_SERIALITF);
-
-
- agnx_write32(ctl, AGNX_PM_SOFTRST, 0x80000033);
- reg = agnx_read32(ctl, 0xec50);
- reg |= 0xf;
- agnx_write32(ctl, 0xec50, reg);
- agnx_write32(ctl, AGNX_PM_SOFTRST, 0x0);
-
-
- reg = agnx_read32(ctl, AGNX_SYSITF_GPIOIN);
- udelay(10);
- reg = agnx_read32(ctl, AGNX_CIR_SERIALITF);
-
- /* Dump the eeprom */
- do {
- char eeprom[0x100000/0x100];
-
- for (i = 0; i < 0x100000; i += 0x100) {
- agnx_write32(ctl, AGNX_CIR_SERIALITF, 0x3000000 + i);
- udelay(13);
- reg = agnx_read32(ctl, AGNX_CIR_SERIALITF);
- udelay(70);
- reg = agnx_read32(ctl, AGNX_CIR_SERIALITF);
- eeprom[i/0x100] = reg & 0xFF;
- udelay(10);
- }
- print_hex_dump_bytes(PFX "EEPROM: ", DUMP_PREFIX_NONE, eeprom,
- ARRAY_SIZE(eeprom));
- } while (0);
-
- spi_rc_write(ctl, RF_CHIP0, 0x26);
- reg = agnx_read32(ctl, AGNX_SPI_RLSW);
-
- /* Initialize the system interface */
- system_itf_init(priv);
-
- might_sleep();
- /* Chip Initialization (Polaris) */
- chip_init(priv);
- might_sleep();
-
- /* Calibrate the antennae */
- antenna_calibrate(priv);
-
- reg = agnx_read32(ctl, 0xec50);
- reg &= ~0x40;
- agnx_write32(ctl, 0xec50, reg);
- agnx_write32(ctl, AGNX_PM_SOFTRST, 0x0);
- agnx_write32(ctl, AGNX_PM_PLLCTL, 0x1);
-
- reg = agnx_read32(ctl, AGNX_BM_BMCTL);
- reg |= 0x8000;
- agnx_write32(ctl, AGNX_BM_BMCTL, reg);
- enable_receiver(priv);
- reg = agnx_read32(ctl, AGNX_SYSITF_SYSMODE);
- reg |= 0x200;
- agnx_write32(ctl, AGNX_SYSITF_SYSMODE, reg);
- enable_receiver(priv);
-
- might_sleep();
- /* Initialize Gain Control Counts */
- gain_ctlcnt_init(priv);
-
- /* Write Initial Station Power Template for this station(#0) */
- sta_power_init(priv, LOCAL_STAID);
-
- might_sleep();
- /* Initialize the rx,td,tm rings, for each node in the ring */
- fill_rings(priv);
-
- might_sleep();
-
-
- agnx_write32(ctl, AGNX_PM_SOFTRST, 0x80000033);
- agnx_write32(ctl, 0xec50, 0xc);
- agnx_write32(ctl, AGNX_PM_SOFTRST, 0x0);
-
- /* FIXME Initialize the transmit control register */
- agnx_write32(ctl, AGNX_TXM_CTL, 0x194c1);
-
- enable_receiver(priv);
-
- might_sleep();
- /* FIXME Set the Receive Control Mac Address to card address */
- mac_address_set(priv);
- enable_receiver(priv);
- might_sleep();
-
- /* Set the recieve request rate */
- /* FIXME Enable the request */
- /* Check packet length */
- /* Set maximum packet length */
-/* agnx_write32(ctl, AGNX_RXM_REQRATE, 0x88195e00); */
-/* enable_receiver(priv); */
-
- /* Set the Receiver BSSID */
- receiver_bssid_set(priv, bssid);
-
- /* FIXME Set to managed mode */
- set_managed_mode(priv);
-/* set_promiscuous_mode(priv); */
-/* set_scan_mode(priv); */
-/* set_learn_mode(priv); */
-/* set_promis_and_managed(priv); */
-/* set_adhoc_mode(priv); */
-
- /* Set the recieve request rate */
- /* Check packet length */
- agnx_write32(ctl, AGNX_RXM_REQRATE, 0x08000000);
- reg = agnx_read32(ctl, AGNX_RXM_REQRATE);
- /* Set maximum packet length */
- reg |= 0x00195e00;
- agnx_write32(ctl, AGNX_RXM_REQRATE, reg);
-
- /* Configure the RX and TX interrupt */
- reg = ENABLE_RX_INTERRUPT | RX_CACHE_LINE | FRAG_LEN_2048 | FRAG_BE;
- agnx_write32(ctl, AGNX_CIR_RXCFG, reg);
- /* FIXME */
- reg = ENABLE_TX_INTERRUPT | TX_CACHE_LINE | FRAG_LEN_2048 | FRAG_BE;
- agnx_write32(ctl, AGNX_CIR_TXCFG, reg);
-
- /* Enable RX TX Interrupts */
- agnx_write32(ctl, AGNX_CIR_RXCTL, 0x80);
- agnx_write32(ctl, AGNX_CIR_TXMCTL, 0x80);
- agnx_write32(ctl, AGNX_CIR_TXDCTL, 0x80);
-
- /* FIXME Set the master control interrupt in block control */
- agnx_write32(ctl, AGNX_CIR_BLKCTL, 0x800);
-
- /* Enable RX and TX queues */
- reg = agnx_read32(ctl, AGNX_CIR_RXCTL);
- reg |= 0x8;
- agnx_write32(ctl, AGNX_CIR_RXCTL, reg);
- reg = agnx_read32(ctl, AGNX_CIR_TXMCTL);
- reg |= 0x8;
- agnx_write32(ctl, AGNX_CIR_TXMCTL, reg);
- reg = agnx_read32(ctl, AGNX_CIR_TXDCTL);
- reg |= 0x8;
- agnx_write32(ctl, AGNX_CIR_TXDCTL, reg);
-
- agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x5);
- /* FIXME */
- /* unknow_register_write(priv); */
- /* Update local card hash entry */
- hash_write(priv, priv->mac_addr, LOCAL_STAID);
-
- might_sleep();
-
- /* FIXME */
- agnx_set_channel(priv, 1);
- might_sleep();
-} /* agnx_card_interface_init */
-
-
-void agnx_hw_init(struct agnx_priv *priv)
-{
- AGNX_TRACE;
- might_sleep();
- card_interface_init(priv);
-}
-
-int agnx_hw_reset(struct agnx_priv *priv)
-{
- return card_full_reset(priv);
-}
-
-int agnx_set_ssid(struct agnx_priv *priv, u8 *ssid, size_t ssid_len)
-{
- AGNX_TRACE;
- return 0;
-}
-
-void agnx_set_bssid(struct agnx_priv *priv, const u8 *bssid)
-{
- receiver_bssid_set(priv, bssid);
-}
diff --git a/drivers/staging/agnx/phy.h b/drivers/staging/agnx/phy.h
deleted file mode 100644
index a955f05361e7..000000000000
--- a/drivers/staging/agnx/phy.h
+++ /dev/null
@@ -1,409 +0,0 @@
-#ifndef AGNX_PHY_H_
-#define AGNX_PHY_H_
-
-#include "agnx.h"
-
-/* Transmission Managment Registers */
-#define AGNX_TXM_BASE 0x0000
-#define AGNX_TXM_CTL 0x0000 /* control register */
-#define AGNX_TXM_ETMF 0x0004 /* enable transmission management functions */
-#define AGNX_TXM_TXTEMP 0x0008 /* transmission template */
-#define AGNX_TXM_RETRYSTAID 0x000c /* Retry Station ID */
-#define AGNX_TXM_TIMESTAMPLO 0x0010 /* Timestamp Lo */
-#define AGNX_TXM_TIMESTAMPHI 0x0014 /* Timestamp Hi */
-#define AGNX_TXM_TXDELAY 0x0018 /* tx delay */
-#define AGNX_TXM_TBTTLO 0x0020 /* tbtt Lo */
-#define AGNX_TXM_TBTTHI 0x0024 /* tbtt Hi */
-#define AGNX_TXM_BEAINTER 0x0028 /* Beacon Interval */
-#define AGNX_TXM_NAV 0x0030 /* NAV */
-#define AGNX_TXM_CFPMDV 0x0034 /* CFP MDV */
-#define AGNX_TXM_CFPERCNT 0x0038 /* CFP period count */
-#define AGNX_TXM_PROBDELAY 0x003c /* probe delay */
-#define AGNX_TXM_LISINTERCNT 0x0040 /* listen interval count */
-#define AGNX_TXM_DTIMPERICNT 0x004c /* DTIM period count */
-
-#define AGNX_TXM_BEACON_CTL 0x005c /* beacon control */
-
-#define AGNX_TXM_SCHEMPCNT 0x007c /* schedule empty count */
-#define AGNX_TXM_MAXTIMOUT 0x0084 /* max timeout exceed count */
-#define AGNX_TXM_MAXCFPTIM 0x0088 /* max CF poll timeout count */
-#define AGNX_TXM_MAXRXTIME 0x008c /* max RX timeout count */
-#define AGNX_TXM_MAXACKTIM 0x0090 /* max ACK timeout count */
-#define AGNX_TXM_DIF01 0x00a0 /* DIF 0-1 */
-#define AGNX_TXM_DIF23 0x00a4 /* DIF 2-3 */
-#define AGNX_TXM_DIF45 0x00a8 /* DIF 4-5 */
-#define AGNX_TXM_DIF67 0x00ac /* DIF 6-7 */
-#define AGNX_TXM_SIFSPIFS 0x00b0 /* SIFS/PIFS */
-#define AGNX_TXM_TIFSEIFS 0x00b4 /* TIFS/EIFS */
-#define AGNX_TXM_MAXCCACNTSLOT 0x00b8 /* max CCA count slot */
-#define AGNX_TXM_SLOTLIMIT 0x00bc /* slot limit/1 msec limit */
-#define AGNX_TXM_CFPOLLRXTIM 0x00f0 /* CF poll RX timeout count */
-#define AGNX_TXM_CFACKT11B 0x00f4 /* CF ack timeout limit for 11b */
-#define AGNX_TXM_CW0 0x0100 /* CW 0 */
-#define AGNX_TXM_SLBEALIM0 0x0108 /* short/long beacon limit 0 */
-#define AGNX_TXM_CW1 0x0120 /* CW 1 */
-#define AGNX_TXM_SLBEALIM1 0x0128 /* short/long beacon limit 1 */
-#define AGNX_TXM_CW2 0x0140 /* CW 2 */
-#define AGNX_TXM_SLBEALIM2 0x0148 /* short/long beacon limit 2 */
-#define AGNX_TXM_CW3 0x0160 /* CW 3 */
-#define AGNX_TXM_SLBEALIM3 0x0168 /* short/long beacon limit 3 */
-#define AGNX_TXM_CW4 0x0180 /* CW 4 */
-#define AGNX_TXM_SLBEALIM4 0x0188 /* short/long beacon limit 4 */
-#define AGNX_TXM_CW5 0x01a0 /* CW 5 */
-#define AGNX_TXM_SLBEALIM5 0x01a8 /* short/long beacon limit 5 */
-#define AGNX_TXM_CW6 0x01c0 /* CW 6 */
-#define AGNX_TXM_SLBEALIM6 0x01c8 /* short/long beacon limit 6 */
-#define AGNX_TXM_CW7 0x01e0 /* CW 7 */
-#define AGNX_TXM_SLBEALIM7 0x01e8 /* short/long beacon limit 7 */
-#define AGNX_TXM_BEACONTEMP 0x1000 /* beacon template */
-#define AGNX_TXM_STAPOWTEMP 0x1a00 /* Station Power Template */
-
-/* Receive Management Control Registers */
-#define AGNX_RXM_BASE 0x2000
-#define AGNX_RXM_REQRATE 0x2000 /* requested rate */
-#define AGNX_RXM_MACHI 0x2004 /* first 4 bytes of mac address */
-#define AGNX_RXM_MACLO 0x2008 /* last 2 bytes of mac address */
-#define AGNX_RXM_BSSIDHI 0x200c /* bssid hi */
-#define AGNX_RXM_BSSIDLO 0x2010 /* bssid lo */
-#define AGNX_RXM_HASH_CMD_FLAG 0x2014 /* Flags for the RX Hash Command Default:0 */
-#define AGNX_RXM_HASH_CMD_HIGH 0x2018 /* The High half of the Hash Command */
-#define AGNX_RXM_HASH_CMD_LOW 0x201c /* The Low half of the Hash Command */
-#define AGNX_RXM_ROUTAB 0x2020 /* routing table */
-#define ROUTAB_SUBTYPE_SHIFT 24
-#define ROUTAB_TYPE_SHIFT 28
-#define ROUTAB_STATUS_SHIFT 30
-#define ROUTAB_RW_SHIFT 31
-#define ROUTAB_ROUTE_DROP 0xf00000 /* Drop */
-#define ROUTAB_ROUTE_CPU 0x400000 /* CPU */
-#define ROUTAB_ROUTE_ENCRY 0x500800 /* Encryption */
-#define ROUTAB_ROUTE_RFP 0x800000 /* RFP */
-
-#define ROUTAB_TYPE_MANAG 0x0 /* Management */
-#define ROUTAB_TYPE_CTL 0x1 /* Control */
-#define ROUTAB_TYPE_DATA 0x2 /* Data */
-
-#define ROUTAB_SUBTYPE_DATA 0x0
-#define ROUTAB_SUBTYPE_DATAACK 0x1
-#define ROUTAB_SUBTYPE_DATAPOLL 0x2
-#define ROUTAB_SUBTYPE_DATAPOLLACK 0x3
-#define ROUTAB_SUBTYPE_NULL 0x4 /* NULL */
-#define ROUTAB_SUBTYPE_NULLACK 0x5
-#define ROUTAB_SUBTYPE_NULLPOLL 0x6
-#define ROUTAB_SUBTYPE_NULLPOLLACK 0x7
-#define ROUTAB_SUBTYPE_QOSDATA 0x8 /* QOS DATA */
-#define ROUTAB_SUBTYPE_QOSDATAACK 0x9
-#define ROUTAB_SUBTYPE_QOSDATAPOLL 0xa
-#define ROUTAB_SUBTYPE_QOSDATAACKPOLL 0xb
-#define ROUTAB_SUBTYPE_QOSNULL 0xc
-#define ROUTAB_SUBTYPE_QOSNULLACK 0xd
-#define ROUTAB_SUBTYPE_QOSNULLPOLL 0xe
-#define ROUTAB_SUBTYPE_QOSNULLPOLLACK 0xf
-#define AGNX_RXM_DELAY11 0x2024 /* delay 11(AB) */
-#define AGNX_RXM_SOF_CNT 0x2028 /* SOF Count */
-#define AGNX_RXM_FRAG_CNT 0x202c /* Fragment Count*/
-#define AGNX_RXM_FCS_CNT 0x2030 /* FCS Count */
-#define AGNX_RXM_BSSID_MISS_CNT 0x2034 /* BSSID Miss Count */
-#define AGNX_RXM_PDU_ERR_CNT 0x2038 /* PDU Error Count */
-#define AGNX_RXM_DEST_MISS_CNT 0x203C /* Destination Miss Count */
-#define AGNX_RXM_DROP_CNT 0x2040 /* Drop Count */
-#define AGNX_RXM_ABORT_CNT 0x2044 /* Abort Count */
-#define AGNX_RXM_RELAY_CNT 0x2048 /* Relay Count */
-#define AGNX_RXM_HASH_MISS_CNT 0x204c /* Hash Miss Count */
-#define AGNX_RXM_SA_HI 0x2050 /* Address of received packet Hi */
-#define AGNX_RXM_SA_LO 0x2054 /* Address of received packet Lo */
-#define AGNX_RXM_HASH_DUMP_LST 0x2100 /* Contains Hash Data */
-#define AGNX_RXM_HASH_DUMP_MST 0x2104 /* Contains Hash Data */
-#define AGNX_RXM_HASH_DUMP_DATA 0x2108 /* The Station ID to dump */
-
-
-/* Encryption Managment */
-#define AGNX_ENCRY_BASE 0x2400
-#define AGNX_ENCRY_WEPKEY0 0x2440 /* wep key #0 */
-#define AGNX_ENCRY_WEPKEY1 0x2444 /* wep key #1 */
-#define AGNX_ENCRY_WEPKEY2 0x2448 /* wep key #2 */
-#define AGNX_ENCRY_WEPKEY3 0x244c /* wep key #3 */
-#define AGNX_ENCRY_CCMRECTL 0x2460 /* ccm replay control */
-
-
-/* Band Management Registers */
-#define AGNX_BM_BASE 0x2c00
-#define AGNX_BM_BMCTL 0x2c00 /* band management control */
-#define AGNX_BM_TXWADDR 0x2c18 /* tx workqueue address start */
-#define AGNX_BM_TXTOPEER 0x2c24 /* transmit to peers */
-#define AGNX_BM_FPLHP 0x2c2c /* free pool list head pointer */
-#define AGNX_BM_FPLTP 0x2c30 /* free pool list tail pointer */
-#define AGNX_BM_FPCNT 0x2c34 /* free pool count */
-#define AGNX_BM_CIPDUWCNT 0x2c38 /* card interface pdu workqueue count */
-#define AGNX_BM_SPPDUWCNT 0x2c3c /* sp pdu workqueue count */
-#define AGNX_BM_RFPPDUWCNT 0x2c40 /* rfp pdu workqueue count */
-#define AGNX_BM_RHPPDUWCNT 0x2c44 /* rhp pdu workqueue count */
-#define AGNX_BM_CIWQCTL 0x2c48 /* Card Interface WorkQueue Control */
-#define AGNX_BM_CPUTXWCTL 0x2c50 /* cpu tx workqueue control */
-#define AGNX_BM_CPURXWCTL 0x2c58 /* cpu rx workqueue control */
-#define AGNX_BM_CPULWCTL 0x2c60 /* cpu low workqueue control */
-#define AGNX_BM_CPUHWCTL 0x2c68 /* cpu high workqueue control */
-#define AGNX_BM_SPTXWCTL 0x2c70 /* sp tx workqueue control */
-#define AGNX_BM_SPRXWCTL 0x2c78 /* sp rx workqueue control */
-#define AGNX_BM_RFPWCTL 0x2c80 /* RFP workqueue control */
-#define AGNX_BM_MTSM 0x2c90 /* Multicast Transmit Station Mask */
-
-/* Card Interface Registers (32bits) */
-#define AGNX_CIR_BASE 0x3000
-#define AGNX_CIR_BLKCTL 0x3000 /* block control*/
-#define AGNX_STAT_TX 0x1
-#define AGNX_STAT_RX 0x2
-#define AGNX_STAT_X 0x4
-/* Below two interrupt flags will be set by our but not CPU or the card */
-#define AGNX_STAT_TXD 0x10
-#define AGNX_STAT_TXM 0x20
-
-#define AGNX_CIR_ADDRWIN 0x3004 /* Addressable Windows*/
-#define AGNX_CIR_ENDIAN 0x3008 /* card endianness */
-#define AGNX_CIR_SERIALITF 0x3020 /* serial interface */
-#define AGNX_CIR_RXCFG 0x3040 /* receive config */
-#define ENABLE_RX_INTERRUPT 0x20
-#define RX_CACHE_LINE 0x8
-/* the RX fragment length */
-#define FRAG_LEN_256 0x0 /* 256B */
-#define FRAG_LEN_512 0x1
-#define FRAG_LEN_1024 0x2
-#define FRAG_LEN_2048 0x3
-#define FRAG_BE 0x10
-#define AGNX_CIR_RXCTL 0x3050 /* receive control */
-/* memory address, chipside */
-#define AGNX_CIR_RXCMSTART 0x3054 /* receive client memory start */
-#define AGNX_CIR_RXCMEND 0x3058 /* receive client memory end */
-/* memory address, pci */
-#define AGNX_CIR_RXHOSTADDR 0x3060 /* receive hostside address */
-/* memory address, chipside */
-#define AGNX_CIR_RXCLIADDR 0x3064 /* receive clientside address */
-#define AGNX_CIR_RXDMACTL 0x3068 /* receive dma control */
-#define AGNX_CIR_TXCFG 0x3080 /* transmit config */
-#define AGNX_CIR_TXMCTL 0x3090 /* Transmit Management Control */
-#define ENABLE_TX_INTERRUPT 0x20
-#define TX_CACHE_LINE 0x8
-#define AGNX_CIR_TXMSTART 0x3094 /* Transmit Management Start */
-#define AGNX_CIR_TXMEND 0x3098 /* Transmit Management End */
-#define AGNX_CIR_TXDCTL 0x30a0 /* transmit data control */
-/* memeory address, chipset */
-#define AGNX_CIR_TXDSTART 0x30a4 /* transmit data start */
-#define AGNX_CIR_TXDEND 0x30a8 /* transmit data end */
-#define AGNX_CIR_TXMHADDR 0x30b0 /* Transmit Management Hostside Address */
-#define AGNX_CIR_TXMCADDR 0x30b4 /* Transmit Management Clientside Address */
-#define AGNX_CIR_TXDMACTL 0x30b8 /* transmit dma control */
-
-
-/* Power Managment Unit */
-#define AGNX_PM_BASE 0x3c00
-#define AGNX_PM_PMCTL 0x3c00 /* PM Control*/
-#define AGNX_PM_MACMSW 0x3c08 /* MAC Manual Slow Work Enable */
-#define AGNX_PM_RFCTL 0x3c0c /* RF Control */
-#define AGNX_PM_PHYMW 0x3c14 /* Phy Mannal Work */
-#define AGNX_PM_SOFTRST 0x3c18 /* PMU Soft Reset */
-#define AGNX_PM_PLLCTL 0x3c1c /* PMU PLL control*/
-#define AGNX_PM_TESTPHY 0x3c24 /* PMU Test Phy */
-
-
-/* Interrupt Control interface */
-#define AGNX_INT_BASE 0x4000
-#define AGNX_INT_STAT 0x4000 /* interrupt status */
-#define AGNX_INT_MASK 0x400c /* interrupt mask */
-/* FIXME */
-#define IRQ_TX_BEACON 0x1 /* TX Beacon */
-#define IRQ_TX_RETRY 0x8 /* TX Retry Interrupt */
-#define IRQ_TX_ACTIVITY 0x10 /* TX Activity */
-#define IRQ_RX_ACTIVITY 0x20 /* RX Activity */
-/* FIXME I guess that instead RX a none exist staion's packet or
- the station hasn't been init */
-#define IRQ_RX_X 0x40
-#define IRQ_RX_Y 0x80 /* RX ? */
-#define IRQ_RX_HASHHIT 0x100 /* RX Hash Hit */
-#define IRQ_RX_FRAME 0x200 /* RX Frame */
-#define IRQ_ERR_INT 0x400 /* Error Interrupt */
-#define IRQ_TX_QUE_FULL 0x800 /* TX Workqueue Full */
-#define IRQ_BANDMAN_ERR 0x10000 /* Bandwidth Management Error */
-#define IRQ_TX_DISABLE 0x20000 /* TX Disable */
-#define IRQ_RX_IVASESKEY 0x80000 /* RX Invalid Session Key */
-#define IRQ_RX_KEYIDMIS 0x100000 /* RX key ID Mismatch */
-#define IRQ_REP_THHIT 0x200000 /* Replay Threshold Hit */
-#define IRQ_TIMER1 0x4000000 /* Timer1 */
-#define IRQ_TIMER_CNT 0x10000000 /* Timer Count */
-#define IRQ_PHY_FASTINT 0x20000000 /* Phy Fast Interrupt */
-#define IRQ_PHY_SLOWINT 0x40000000 /* Phy Slow Interrupt */
-#define IRQ_OTHER 0x80000000 /* Unknow interrupt */
-#define AGNX_IRQ_ALL 0xffffffff
-
-/* System Interface */
-#define AGNX_SYSITF_BASE 0x4400
-#define AGNX_SYSITF_SYSMODE 0x4400 /* system mode */
-#define AGNX_SYSITF_GPIOIN 0x4410 /* GPIO In */
-/* PIN lines for leds? */
-#define AGNX_SYSITF_GPIOUT 0x4414 /* GPIO Out */
-
-/* Timer Control */
-#define AGNX_TIMCTL_TIMER1 0x4800 /* Timer 1 */
-#define AGNX_TIMCTL_TIM1CTL 0x4808 /* Timer 1 Control */
-
-
-/* Antenna Calibration Interface */
-#define AGNX_ACI_BASE 0x5000
-#define AGNX_ACI_MODE 0x5000 /* Mode */
-#define AGNX_ACI_MEASURE 0x5004 /* Measure */
-#define AGNX_ACI_SELCHAIN 0x5008 /* Select Chain */
-#define AGNX_ACI_LEN 0x500c /* Length */
-#define AGNX_ACI_TIMER1 0x5018 /* Timer 1 */
-#define AGNX_ACI_TIMER2 0x501c /* Timer 2 */
-#define AGNX_ACI_OFFSET 0x5020 /* Offset */
-#define AGNX_ACI_STATUS 0x5030 /* Status */
-#define CALI_IDLE 0x0
-#define CALI_DONE 0x1
-#define CALI_BUSY 0x2
-#define CALI_ERR 0x3
-#define AGNX_ACI_AICCHA0OVE 0x5034 /* AIC Channel 0 Override */
-#define AGNX_ACI_AICCHA1OVE 0x5038 /* AIC Channel 1 Override */
-
-/* Gain Control Registers */
-#define AGNX_GCR_BASE 0x9000
-/* threshold of primary antenna */
-#define AGNX_GCR_THD0A 0x9000 /* threshold? D0 A */
-/* low threshold of primary antenna */
-#define AGNX_GCR_THD0AL 0x9004 /* threshold? D0 A low */
-/* threshold of secondary antenna */
-#define AGNX_GCR_THD0B 0x9008 /* threshold? D0_B */
-#define AGNX_GCR_DUNSAT 0x900c /* d unsaturated */
-#define AGNX_GCR_DSAT 0x9010 /* d saturated */
-#define AGNX_GCR_DFIRCAL 0x9014 /* D Fir/Cal */
-#define AGNX_GCR_DGCTL11A 0x9018 /* d gain control 11a */
-#define AGNX_GCR_DGCTL11B 0x901c /* d gain control 11b */
-/* strength of gain */
-#define AGNX_GCR_GAININIT 0x9020 /* gain initialization */
-#define AGNX_GCR_THNOSIG 0x9024 /* threhold no signal */
-#define AGNX_GCR_COARSTEP 0x9028 /* coarse stepping */
-#define AGNX_GCR_SIFST11A 0x902c /* sifx time 11a */
-#define AGNX_GCR_SIFST11B 0x9030 /* sifx time 11b */
-#define AGNX_GCR_CWDETEC 0x9034 /* cw detection */
-#define AGNX_GCR_0X38 0x9038 /* ???? */
-#define AGNX_GCR_BOACT 0x903c /* BO Active */
-#define AGNX_GCR_BOINACT 0x9040 /* BO Inactive */
-#define AGNX_GCR_BODYNA 0x9044 /* BO dynamic */
-/* 802.11 mode(a,b,g) */
-#define AGNX_GCR_DISCOVMOD 0x9048 /* discovery mode */
-#define AGNX_GCR_NLISTANT 0x904c /* number of listening antenna */
-#define AGNX_GCR_NACTIANT 0x9050 /* number of active antenna */
-#define AGNX_GCR_NMEASANT 0x9054 /* number of measuring antenna */
-#define AGNX_GCR_NCAPTANT 0x9058 /* number of capture antenna */
-#define AGNX_GCR_THCAP11A 0x905c /* threshold capture 11a */
-#define AGNX_GCR_THCAP11B 0x9060 /* threshold capture 11b */
-#define AGNX_GCR_THCAPRX11A 0x9064 /* threshold capture rx 11a */
-#define AGNX_GCR_THCAPRX11B 0x9068 /* threshold capture rx 11b */
-#define AGNX_GCR_THLEVDRO 0x906c /* threshold level drop */
-#define AGNX_GCR_GAINSET0 0x9070 /* Gainset 0 */
-#define AGNX_GCR_GAINSET1 0x9074 /* Gainset 1 */
-#define AGNX_GCR_GAINSET2 0x9078 /* Gainset 2 */
-#define AGNX_GCR_MAXRXTIME11A 0x907c /* maximum rx time 11a */
-#define AGNX_GCR_MAXRXTIME11B 0x9080 /* maximum rx time 11b */
-#define AGNX_GCR_CORRTIME 0x9084 /* correction time */
-/* reset the subsystem, 0 = disable, 1 = enable */
-#define AGNX_GCR_RSTGCTL 0x9088 /* reset gain control */
-/* channel receiving */
-#define AGNX_GCR_RXCHANEL 0x908c /* receive channel */
-#define AGNX_GCR_NOISE0 0x9090 /* Noise 0 */
-#define AGNX_GCR_NOISE1 0x9094 /* Noise 1 */
-#define AGNX_GCR_NOISE2 0x9098 /* Noise 2 */
-#define AGNX_GCR_SIGHTH 0x909c /* Signal High Threshold */
-#define AGNX_GCR_SIGLTH 0x90a0 /* Signal Low Threshold */
-#define AGNX_GCR_CORRDROP 0x90a4 /* correction drop */
-/* threshold of tertiay antenna */
-#define AGNX_GCR_THCD 0x90a8 /* threshold? CD */
-#define AGNX_GCR_THCS 0x90ac /* threshold? CS */
-#define AGNX_GCR_MAXPOWDIFF 0x90b8 /* maximum power difference */
-#define AGNX_GCR_TRACNT4 0x90ec /* Transition Count 4 */
-#define AGNX_GCR_TRACNT5 0x90f0 /* transition count 5 */
-#define AGNX_GCR_TRACNT6 0x90f4 /* transition count 6 */
-#define AGNX_GCR_TRACNT7 0x90f8 /* transition coutn 7 */
-#define AGNX_GCR_TESTBUS 0x911c /* test bus */
-#define AGNX_GCR_CHAINNUM 0x9120 /* Number of Chains */
-#define AGNX_GCR_ANTCFG 0x9124 /* Antenna Config */
-#define AGNX_GCR_THJUMP 0x912c /* threhold jump */
-#define AGNX_GCR_THPOWER 0x9130 /* threshold power */
-#define AGNX_GCR_THPOWCLIP 0x9134 /* threshold power clip*/
-#define AGNX_GCR_FORCECTLCLK 0x9138 /* Force Gain Control Clock */
-#define AGNX_GCR_GAINSETWRITE 0x913c /* Gainset Write */
-#define AGNX_GCR_THD0BTFEST 0x9140 /* threshold d0 b tf estimate */
-#define AGNX_GCR_THRX11BPOWMIN 0x9144 /* threshold rx 11b power minimum */
-#define AGNX_GCR_0X14c 0x914c /* ?? */
-#define AGNX_GCR_0X150 0x9150 /* ?? */
-#define AGNX_GCR_RXOVERIDE 0x9194 /* recieve override */
-#define AGNX_GCR_WATCHDOG 0x91b0 /* watchdog timeout */
-
-
-/* Spi Interface */
-#define AGNX_SPI_BASE 0xdc00
-#define AGNX_SPI_CFG 0xdc00 /* spi configuration */
-/* Only accept 16 bits */
-#define AGNX_SPI_WMSW 0xdc04 /* write most significant word */
-/* Only accept 16 bits */
-#define AGNX_SPI_WLSW 0xdc08 /* write least significant word */
-#define AGNX_SPI_CTL 0xdc0c /* spi control */
-#define AGNX_SPI_RMSW 0xdc10 /* read most significant word */
-#define AGNX_SPI_RLSW 0xdc14 /* read least significant word */
-/* SPI Control Mask */
-#define SPI_READ_CTL 0x4000 /* read control */
-#define SPI_BUSY_CTL 0x8000 /* busy control */
-/* RF and synth chips in spi */
-#define RF_CHIP0 0x400
-#define RF_CHIP1 0x800
-#define RF_CHIP2 0x1000
-#define SYNTH_CHIP 0x2000
-
-/* Unknown register */
-#define AGNX_UNKNOWN_BASE 0x7800
-
-/* FIXME MonitorGain */
-#define AGNX_MONGCR_BASE 0x12000
-
-/* Gain Table */
-#define AGNX_GAIN_TABLE 0x12400
-
-/* The initial FIR coefficient table */
-#define AGNX_FIR_BASE 0x19804
-
-#define AGNX_ENGINE_LOOKUP_TBL 0x800
-
-/* eeprom commands */
-#define EEPROM_CMD_NULL 0x0 /* NULL */
-#define EEPROM_CMD_WRITE 0x2 /* write */
-#define EEPROM_CMD_READ 0x3 /* read */
-#define EEPROM_CMD_STATUSREAD 0x5 /* status register read */
-#define EEPROM_CMD_WRITEENABLE 0x6 /* write enable */
-#define EEPROM_CMD_CONFIGURE 0x7 /* configure */
-
-#define EEPROM_DATAFORCOFIGURE 0x6 /* ??? */
-
-/* eeprom address */
-#define EEPROM_ADDR_SUBVID 0x0 /* Sub Vendor ID */
-#define EEPROM_ADDR_SUBSID 0x2 /* Sub System ID */
-#define EEPROM_ADDR_MACADDR 0x146 /* MAC Address */
-#define EEPROM_ADDR_LOTYPE 0x14f /* LO type */
-
-struct agnx_eeprom {
- u8 data; /* date */
- u16 address; /* address in EEPROM */
- u8 cmd; /* command, unknown, status */
-} __attribute__((__packed__));
-
-#define AGNX_EEPROM_COMMAND_SHIFT 5
-#define AGNX_EEPROM_COMMAND_STAT 0x01
-
-void disable_receiver(struct agnx_priv *priv);
-void enable_receiver(struct agnx_priv *priv);
-u8 read_from_eeprom(struct agnx_priv *priv, u16 address);
-void agnx_hw_init(struct agnx_priv *priv);
-int agnx_hw_reset(struct agnx_priv *priv);
-int agnx_set_ssid(struct agnx_priv *priv, u8 *ssid, size_t ssid_len);
-void agnx_set_bssid(struct agnx_priv *priv, const u8 *bssid);
-void enable_power_saving(struct agnx_priv *priv);
-void disable_power_saving(struct agnx_priv *priv);
-void calibrate_antenna_period(unsigned long data);
-
-#endif /* AGNX_PHY_H_ */
diff --git a/drivers/staging/agnx/rf.c b/drivers/staging/agnx/rf.c
deleted file mode 100644
index 42e457a1844f..000000000000
--- a/drivers/staging/agnx/rf.c
+++ /dev/null
@@ -1,893 +0,0 @@
-/**
- * Airgo MIMO wireless driver
- *
- * Copyright (c) 2007 Li YanBo <dreamfly281@gmail.com>
-
- * Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer
- * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin
-
- * 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/pci.h>
-#include <linux/delay.h>
-#include "agnx.h"
-#include "debug.h"
-#include "phy.h"
-#include "table.h"
-
-/* FIXME! */
-static inline void spi_write(void __iomem *region, u32 chip_ids, u32 sw,
- u16 size, u32 control)
-{
- u32 reg;
- u32 lsw = sw & 0xffff; /* lower 16 bits of sw*/
- u32 msw = sw >> 16; /* high 16 bits of sw */
-
- /* FIXME Write Most Significant Word of the 32bit data to MSW */
- /* FIXME And Least Significant Word to LSW */
- iowrite32((lsw), region + AGNX_SPI_WLSW);
- iowrite32((msw), region + AGNX_SPI_WMSW);
- reg = chip_ids | size | control;
- /* Write chip id(s), write size and busy control to Control Register */
- iowrite32((reg), region + AGNX_SPI_CTL);
- /* Wait for Busy control to clear */
- spi_delay();
-}
-
-/*
- * Write to SPI Synth register
- */
-static inline void spi_sy_write(void __iomem *region, u32 chip_ids, u32 sw)
-{
- /* FIXME the size 0x15 is a magic value*/
- spi_write(region, chip_ids, sw, 0x15, SPI_BUSY_CTL);
-}
-
-/*
- * Write to SPI RF register
- */
-static inline void spi_rf_write(void __iomem *region, u32 chip_ids, u32 sw)
-{
- /* FIXME the size 0xd is a magic value*/
- spi_write(region, chip_ids, sw, 0xd, SPI_BUSY_CTL);
-} /* spi_rf_write */
-
-/*
- * Write to SPI with Read Control bit set
- */
-inline void spi_rc_write(void __iomem *region, u32 chip_ids, u32 sw)
-{
- /* FIXME the size 0xe5 is a magic value */
- spi_write(region, chip_ids, sw, 0xe5, SPI_BUSY_CTL|SPI_READ_CTL);
-}
-
-/* Get the active chains's count */
-static int get_active_chains(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- int num = 0;
- u32 reg;
- AGNX_TRACE;
-
- spi_rc_write(ctl, RF_CHIP0, 0x21);
- reg = agnx_read32(ctl, AGNX_SPI_RLSW);
- if (reg == 1)
- num++;
-
- spi_rc_write(ctl, RF_CHIP1, 0x21);
- reg = agnx_read32(ctl, AGNX_SPI_RLSW);
- if (reg == 1)
- num++;
-
- spi_rc_write(ctl, RF_CHIP2, 0x21);
- reg = agnx_read32(ctl, AGNX_SPI_RLSW);
- if (reg == 1)
- num++;
-
- spi_rc_write(ctl, RF_CHIP0, 0x26);
- reg = agnx_read32(ctl, AGNX_SPI_RLSW);
- if (0x33 != reg)
- printk(KERN_WARNING PFX "Unmatched rf chips result\n");
-
- return num;
-} /* get_active_chains */
-
-void rf_chips_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- int num;
- AGNX_TRACE;
-
- if (priv->revid == 1) {
- reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT);
- reg |= 0x8;
- agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg);
- }
-
- /* Set SPI clock speed to 200NS */
- reg = agnx_read32(ctl, AGNX_SPI_CFG);
- reg &= ~0xF;
- reg |= 0x3;
- agnx_write32(ctl, AGNX_SPI_CFG, reg);
-
- /* Set SPI clock speed to 50NS */
- reg = agnx_read32(ctl, AGNX_SPI_CFG);
- reg &= ~0xF;
- reg |= 0x1;
- agnx_write32(ctl, AGNX_SPI_CFG, reg);
-
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1101);
-
- num = get_active_chains(priv);
- printk(KERN_INFO PFX "Active chains are %d\n", num);
-
- reg = agnx_read32(ctl, AGNX_SPI_CFG);
- reg &= ~0xF;
- agnx_write32(ctl, AGNX_SPI_CFG, reg);
-
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1908);
-} /* rf_chips_init */
-
-
-static u32 channel_tbl[15][9] = {
- {0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {1, 0x00, 0x00, 0x624, 0x00, 0x1a4, 0x28, 0x00, 0x1e},
- {2, 0x00, 0x00, 0x615, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
- {3, 0x00, 0x00, 0x61a, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
- {4, 0x00, 0x00, 0x61f, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
- {5, 0x00, 0x00, 0x624, 0x00, 0x1ae, 0x28, 0x00, 0x1e},
- {6, 0x00, 0x00, 0x61f, 0x00, 0x1b3, 0x28, 0x00, 0x1e},
- {7, 0x00, 0x00, 0x624, 0x00, 0x1b3, 0x28, 0x00, 0x1e},
- {8, 0x00, 0x00, 0x629, 0x00, 0x1b3, 0x28, 0x00, 0x1e},
- {9, 0x00, 0x00, 0x624, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
- {10, 0x00, 0x00, 0x629, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
- {11, 0x00, 0x00, 0x62e, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
- {12, 0x00, 0x00, 0x633, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
- {13, 0x00, 0x00, 0x628, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
- {14, 0x00, 0x00, 0x644, 0x00, 0x1b8, 0x28, 0x00, 0x1e},
-};
-
-
-static inline void
-channel_tbl_write(struct agnx_priv *priv, unsigned int channel, unsigned int reg_num)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
-
- reg = channel_tbl[channel][reg_num];
- reg <<= 4;
- reg |= reg_num;
- spi_sy_write(ctl, SYNTH_CHIP, reg);
-}
-
-static void synth_freq_set(struct agnx_priv *priv, unsigned int channel)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- AGNX_TRACE;
-
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
-
- /* Set the Clock bits to 50NS */
- reg = agnx_read32(ctl, AGNX_SPI_CFG);
- reg &= ~0xF;
- reg |= 0x1;
- agnx_write32(ctl, AGNX_SPI_CFG, reg);
-
- /* Write 0x00c0 to LSW and 0x3 to MSW of Synth Chip */
- spi_sy_write(ctl, SYNTH_CHIP, 0x300c0);
-
- spi_sy_write(ctl, SYNTH_CHIP, 0x32);
-
- /* # Write to Register 1 on the Synth Chip */
- channel_tbl_write(priv, channel, 1);
- /* # Write to Register 3 on the Synth Chip */
- channel_tbl_write(priv, channel, 3);
- /* # Write to Register 6 on the Synth Chip */
- channel_tbl_write(priv, channel, 6);
- /* # Write to Register 5 on the Synth Chip */
- channel_tbl_write(priv, channel, 5);
- /* # Write to register 8 on the Synth Chip */
- channel_tbl_write(priv, channel, 8);
-
- /* FIXME Clear the clock bits */
- reg = agnx_read32(ctl, AGNX_SPI_CFG);
- reg &= ~0xf;
- agnx_write32(ctl, AGNX_SPI_CFG, reg);
-} /* synth_chip_init */
-
-
-static void antenna_init(struct agnx_priv *priv, int num_antenna)
-{
- void __iomem *ctl = priv->ctl;
-
- switch (num_antenna) {
- case 1:
- agnx_write32(ctl, AGNX_GCR_NLISTANT, 1);
- agnx_write32(ctl, AGNX_GCR_NMEASANT, 1);
- agnx_write32(ctl, AGNX_GCR_NACTIANT, 1);
- agnx_write32(ctl, AGNX_GCR_NCAPTANT, 1);
-
- agnx_write32(ctl, AGNX_GCR_ANTCFG, 7);
- agnx_write32(ctl, AGNX_GCR_BOACT, 34);
- agnx_write32(ctl, AGNX_GCR_BOINACT, 34);
- agnx_write32(ctl, AGNX_GCR_BODYNA, 30);
-
- agnx_write32(ctl, AGNX_GCR_THD0A, 125);
- agnx_write32(ctl, AGNX_GCR_THD0AL, 100);
- agnx_write32(ctl, AGNX_GCR_THD0B, 90);
-
- agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 80);
- agnx_write32(ctl, AGNX_GCR_SIGHTH, 100);
- agnx_write32(ctl, AGNX_GCR_SIGLTH, 16);
- break;
- case 2:
- agnx_write32(ctl, AGNX_GCR_NLISTANT, 2);
- agnx_write32(ctl, AGNX_GCR_NMEASANT, 2);
- agnx_write32(ctl, AGNX_GCR_NACTIANT, 2);
- agnx_write32(ctl, AGNX_GCR_NCAPTANT, 2);
- agnx_write32(ctl, AGNX_GCR_ANTCFG, 15);
- agnx_write32(ctl, AGNX_GCR_BOACT, 36);
- agnx_write32(ctl, AGNX_GCR_BOINACT, 36);
- agnx_write32(ctl, AGNX_GCR_BODYNA, 32);
- agnx_write32(ctl, AGNX_GCR_THD0A, 120);
- agnx_write32(ctl, AGNX_GCR_THD0AL, 100);
- agnx_write32(ctl, AGNX_GCR_THD0B, 80);
- agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 70);
- agnx_write32(ctl, AGNX_GCR_SIGHTH, 100);
- agnx_write32(ctl, AGNX_GCR_SIGLTH, 32);
- break;
- case 3:
- agnx_write32(ctl, AGNX_GCR_NLISTANT, 3);
- agnx_write32(ctl, AGNX_GCR_NMEASANT, 3);
- agnx_write32(ctl, AGNX_GCR_NACTIANT, 3);
- agnx_write32(ctl, AGNX_GCR_NCAPTANT, 3);
- agnx_write32(ctl, AGNX_GCR_ANTCFG, 31);
- agnx_write32(ctl, AGNX_GCR_BOACT, 36);
- agnx_write32(ctl, AGNX_GCR_BOINACT, 36);
- agnx_write32(ctl, AGNX_GCR_BODYNA, 32);
- agnx_write32(ctl, AGNX_GCR_THD0A, 100);
- agnx_write32(ctl, AGNX_GCR_THD0AL, 100);
- agnx_write32(ctl, AGNX_GCR_THD0B, 70);
- agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 70);
- agnx_write32(ctl, AGNX_GCR_SIGHTH, 100);
- agnx_write32(ctl, AGNX_GCR_SIGLTH, 48);
-/* agnx_write32(ctl, AGNX_GCR_SIGLTH, 16); */
- break;
- default:
- printk(KERN_WARNING PFX "Unknow antenna number\n");
- }
-} /* antenna_init */
-
-static void chain_update(struct agnx_priv *priv, u32 chain)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- AGNX_TRACE;
-
- spi_rc_write(ctl, RF_CHIP0, 0x20);
- reg = agnx_read32(ctl, AGNX_SPI_RLSW);
-
- if (reg == 0x4)
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, reg|0x1000);
- else if (reg != 0x0)
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000);
- else {
- if (chain == 3 || chain == 6) {
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, reg|0x1000);
- agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
- } else if (chain == 2 || chain == 4) {
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, reg|0x1000);
- spi_rf_write(ctl, RF_CHIP2, 0x1005);
- agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x824);
- } else if (chain == 1) {
- spi_rf_write(ctl, RF_CHIP0, reg|0x1000);
- spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1004);
- agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xc36);
- }
- }
-
- spi_rc_write(ctl, RF_CHIP0, 0x22);
- reg = agnx_read32(ctl, AGNX_SPI_RLSW);
-
- switch (reg) {
- case 0:
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1005);
- break;
- case 1:
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
- break;
- case 2:
- if (chain == 6 || chain == 4) {
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1202);
- spi_rf_write(ctl, RF_CHIP2, 0x1005);
- } else if (chain < 3) {
- spi_rf_write(ctl, RF_CHIP0, 0x1202);
- spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1005);
- }
- break;
- default:
- if (chain == 3) {
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203);
- spi_rf_write(ctl, RF_CHIP2, 0x1201);
- } else if (chain == 2) {
- spi_rf_write(ctl, RF_CHIP0, 0x1203);
- spi_rf_write(ctl, RF_CHIP2, 0x1200);
- spi_rf_write(ctl, RF_CHIP1, 0x1201);
- } else if (chain == 1) {
- spi_rf_write(ctl, RF_CHIP0, 0x1203);
- spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1200);
- } else if (chain == 4) {
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203);
- spi_rf_write(ctl, RF_CHIP2, 0x1201);
- } else {
- spi_rf_write(ctl, RF_CHIP0, 0x1203);
- spi_rf_write(ctl, RF_CHIP1|RF_CHIP2, 0x1201);
- }
- }
-} /* chain_update */
-
-static void antenna_config(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- AGNX_TRACE;
-
- /* Write 0x0 to the TX Management Control Register Enable bit */
- reg = agnx_read32(ctl, AGNX_TXM_CTL);
- reg &= ~0x1;
- agnx_write32(ctl, AGNX_TXM_CTL, reg);
-
- /* FIXME */
- /* Set initial value based on number of Antennae */
- antenna_init(priv, 3);
-
- /* FIXME Update Power Templates for current valid Stations */
- /* sta_power_init(priv, 0);*/
-
- /* FIXME the number of chains should get from eeprom*/
- chain_update(priv, AGNX_CHAINS_MAX);
-} /* antenna_config */
-
-void calibrate_oscillator(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- AGNX_TRACE;
-
- spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
- reg = agnx_read32(ctl, AGNX_GCR_GAINSET1);
- reg |= 0x10;
- agnx_write32(ctl, AGNX_GCR_GAINSET1, reg);
-
- agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 1);
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 1);
-
- agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);
-
- agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27);
- agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
- /* (Residual DC Calibration) to Calibration Mode */
- agnx_write32(ctl, AGNX_ACI_MODE, 0x2);
-
- spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x1004);
- agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);
- /* (TX LO Calibration) to Calibration Mode */
- agnx_write32(ctl, AGNX_ACI_MODE, 0x4);
-
- do {
- u32 reg1, reg2, reg3;
- /* Enable Power Saving Control */
- enable_power_saving(priv);
- /* Save the following registers to restore */
- reg1 = ioread32(ctl + 0x11000);
- reg2 = ioread32(ctl + 0xec50);
- reg3 = ioread32(ctl + 0xec54);
- wmb();
-
- agnx_write32(ctl, 0x11000, 0xcfdf);
- agnx_write32(ctl, 0xec50, 0x70);
- /* Restore the registers */
- agnx_write32(ctl, 0x11000, reg1);
- agnx_write32(ctl, 0xec50, reg2);
- agnx_write32(ctl, 0xec54, reg3);
- /* Disable Power Saving Control */
- disable_power_saving(priv);
- } while (0);
-
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0);
-} /* calibrate_oscillator */
-
-
-static void radio_channel_set(struct agnx_priv *priv, unsigned int channel)
-{
- void __iomem *ctl = priv->ctl;
- unsigned int freq = priv->band.channels[channel - 1].center_freq;
- u32 reg;
- AGNX_TRACE;
-
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
- /* Set SPI Clock to 50 Ns */
- reg = agnx_read32(ctl, AGNX_SPI_CFG);
- reg &= ~0xF;
- reg |= 0x1;
- agnx_write32(ctl, AGNX_SPI_CFG, reg);
-
- /* Clear the Disable Tx interrupt bit in Interrupt Mask */
-/* reg = agnx_read32(ctl, AGNX_INT_MASK); */
-/* reg &= ~IRQ_TX_DISABLE; */
-/* agnx_write32(ctl, AGNX_INT_MASK, reg); */
-
- /* Band Selection */
- reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT);
- reg |= 0x8;
- agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg);
-
- /* FIXME Set the SiLabs Chip Frequency */
- synth_freq_set(priv, channel);
-
- reg = agnx_read32(ctl, AGNX_PM_SOFTRST);
- reg |= 0x80100030;
- agnx_write32(ctl, AGNX_PM_SOFTRST, reg);
- reg = agnx_read32(ctl, AGNX_PM_PLLCTL);
- reg |= 0x20009;
- agnx_write32(ctl, AGNX_PM_PLLCTL, reg);
-
- agnx_write32(ctl, AGNX_SYSITF_GPIOUT, 0x5);
-
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1100);
-
- /* Load the MonitorGain Table */
- monitor_gain_table_init(priv);
-
- /* Load the TX Fir table */
- tx_fir_table_init(priv);
-
- reg = agnx_read32(ctl, AGNX_PM_PMCTL);
- reg |= 0x8;
- agnx_write32(ctl, AGNX_PM_PMCTL, reg);
-
- spi_rc_write(ctl, RF_CHIP0|RF_CHIP1, 0x22);
- udelay(80);
- reg = agnx_read32(ctl, AGNX_SPI_RLSW);
-
-
- agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xff);
- agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
-
- reg = agnx_read32(ctl, 0xec50);
- reg |= 0x4f;
- agnx_write32(ctl, 0xec50, reg);
-
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
- agnx_write32(ctl, 0x11008, 0x1);
- agnx_write32(ctl, 0x1100c, 0x0);
- agnx_write32(ctl, 0x11008, 0x0);
- agnx_write32(ctl, 0xec50, 0xc);
-
- agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
- agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
- agnx_write32(ctl, 0x11010, 0x6e);
- agnx_write32(ctl, 0x11014, 0x6c);
-
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1201);
-
- /* Calibrate the Antenna */
- /* antenna_calibrate(priv); */
- /* Calibrate the TxLocalOscillator */
- calibrate_oscillator(priv);
-
- reg = agnx_read32(ctl, AGNX_PM_PMCTL);
- reg &= ~0x8;
- agnx_write32(ctl, AGNX_PM_PMCTL, reg);
- agnx_write32(ctl, AGNX_GCR_GAININIT, 0xa);
- agnx_write32(ctl, AGNX_GCR_THCD, 0x0);
-
- agnx_write32(ctl, 0x11018, 0xb);
- agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x0);
-
- /* Write Frequency to Gain Control Channel */
- agnx_write32(ctl, AGNX_GCR_RXCHANEL, freq);
- /* Write 0x140000/Freq to 0x9c08 */
- reg = 0x140000/freq;
- agnx_write32(ctl, 0x9c08, reg);
-
- reg = agnx_read32(ctl, AGNX_PM_SOFTRST);
- reg &= ~0x80100030;
- agnx_write32(ctl, AGNX_PM_SOFTRST, reg);
-
- reg = agnx_read32(ctl, AGNX_PM_PLLCTL);
- reg &= ~0x20009;
- reg |= 0x1;
- agnx_write32(ctl, AGNX_PM_PLLCTL, reg);
-
- agnx_write32(ctl, AGNX_ACI_MODE, 0x0);
-
-/* FIXME According to Number of Chains: */
-
-/* 1. 1: */
-/* 1. Write 0x1203 to RF Chip 0 */
-/* 2. Write 0x1200 to RF Chips 1 +2 */
-/* 2. 2: */
-/* 1. Write 0x1203 to RF Chip 0 */
-/* 2. Write 0x1200 to RF Chip 2 */
-/* 3. Write 0x1201 to RF Chip 1 */
-/* 3. 3: */
-/* 1. Write 0x1203 to RF Chip 0 */
-/* 2. Write 0x1201 to RF Chip 1 + 2 */
-/* 4. 4: */
-/* 1. Write 0x1203 to RF Chip 0 + 1 */
-/* 2. Write 0x1200 to RF Chip 2 */
-
-/* 5. 6: */
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1, 0x1203);
- spi_rf_write(ctl, RF_CHIP2, 0x1201);
-
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1000);
- agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
-
- /* FIXME Set the Disable Tx interrupt bit in Interrupt Mask
- (Or 0x20000 to Interrupt Mask) */
-/* reg = agnx_read32(ctl, AGNX_INT_MASK); */
-/* reg |= IRQ_TX_DISABLE; */
-/* agnx_write32(ctl, AGNX_INT_MASK, reg); */
-
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);
-
- /* Configure the Antenna */
- antenna_config(priv);
-
- /* Write 0x0 to Discovery Mode Enable detect G, B, A packet? */
- agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0);
-
- reg = agnx_read32(ctl, AGNX_RXM_REQRATE);
- reg |= 0x80000000;
- agnx_write32(ctl, AGNX_RXM_REQRATE, reg);
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);
-
- /* enable radio on and the power LED */
- reg = agnx_read32(ctl, AGNX_SYSITF_GPIOUT);
- reg &= ~0x1;
- reg |= 0x2;
- agnx_write32(ctl, AGNX_SYSITF_GPIOUT, reg);
-
- reg = agnx_read32(ctl, AGNX_TXM_CTL);
- reg |= 0x1;
- agnx_write32(ctl, AGNX_TXM_CTL, reg);
-} /* radio_channel_set */
-
-static void base_band_filter_calibrate(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
-
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1700);
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1001);
- agnx_write32(ctl, AGNX_GCR_FORCECTLCLK, 0x0);
- spi_rc_write(ctl, RF_CHIP0, 0x27);
- spi_rc_write(ctl, RF_CHIP1, 0x27);
- spi_rc_write(ctl, RF_CHIP2, 0x27);
- agnx_write32(ctl, AGNX_GCR_FORCECTLCLK, 0x1);
-}
-
-static void print_offset(struct agnx_priv *priv, u32 chain)
-{
- void __iomem *ctl = priv->ctl;
- u32 offset;
-
- iowrite32((chain), ctl + AGNX_ACI_SELCHAIN);
- udelay(10);
- offset = (ioread32(ctl + AGNX_ACI_OFFSET));
- printk(PFX "Chain is 0x%x, Offset is 0x%x\n", chain, offset);
-}
-
-void print_offsets(struct agnx_priv *priv)
-{
- print_offset(priv, 0);
- print_offset(priv, 4);
- print_offset(priv, 1);
- print_offset(priv, 5);
- print_offset(priv, 2);
- print_offset(priv, 6);
-}
-
-
-struct chains {
- u32 cali; /* calibrate value*/
-
-#define NEED_CALIBRATE 0
-#define SUCCESS_CALIBRATE 1
- int status;
-};
-
-static void chain_calibrate(struct agnx_priv *priv, struct chains *chains,
- unsigned int num)
-{
- void __iomem *ctl = priv->ctl;
- u32 calibra = chains[num].cali;
-
- if (num < 3)
- calibra |= 0x1400;
- else
- calibra |= 0x1500;
-
- switch (num) {
- case 0:
- case 4:
- spi_rf_write(ctl, RF_CHIP0, calibra);
- break;
- case 1:
- case 5:
- spi_rf_write(ctl, RF_CHIP1, calibra);
- break;
- case 2:
- case 6:
- spi_rf_write(ctl, RF_CHIP2, calibra);
- break;
- default:
- BUG();
- }
-} /* chain_calibrate */
-
-static inline void get_calibrete_value(struct agnx_priv *priv, struct chains *chains,
- unsigned int num)
-{
- void __iomem *ctl = priv->ctl;
- u32 offset;
-
- iowrite32((num), ctl + AGNX_ACI_SELCHAIN);
- /* FIXME */
- udelay(10);
- offset = (ioread32(ctl + AGNX_ACI_OFFSET));
-
- if (offset < 0xf) {
- chains[num].status = SUCCESS_CALIBRATE;
- return;
- }
-
- if (num == 0 || num == 1 || num == 2) {
- if (0 == chains[num].cali)
- chains[num].cali = 0xff;
- else
- chains[num].cali--;
- } else
- chains[num].cali++;
-
- chains[num].status = NEED_CALIBRATE;
-}
-
-static inline void calibra_delay(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- unsigned int i = 100;
-
- wmb();
- while (--i) {
- reg = (ioread32(ctl + AGNX_ACI_STATUS));
- if (reg == 0x4000)
- break;
- udelay(10);
- }
- if (!i)
- printk(PFX "calibration failed\n");
-}
-
-void do_calibration(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- struct chains chains[7];
- unsigned int i, j;
- AGNX_TRACE;
-
- for (i = 0; i < 7; i++) {
- if (i == 3)
- continue;
-
- chains[i].cali = 0x7f;
- chains[i].status = NEED_CALIBRATE;
- }
-
- /* FIXME 0x300 is a magic number */
- for (j = 0; j < 0x300; j++) {
- if (chains[0].status == SUCCESS_CALIBRATE &&
- chains[1].status == SUCCESS_CALIBRATE &&
- chains[2].status == SUCCESS_CALIBRATE &&
- chains[4].status == SUCCESS_CALIBRATE &&
- chains[5].status == SUCCESS_CALIBRATE &&
- chains[6].status == SUCCESS_CALIBRATE)
- break;
-
- /* Attention, there is no chain 3 */
- for (i = 0; i < 7; i++) {
- if (i == 3)
- continue;
- if (chains[i].status == NEED_CALIBRATE)
- chain_calibrate(priv, chains, i);
- }
- /* Write 0x1 to Calibration Measure */
- iowrite32((0x1), ctl + AGNX_ACI_MEASURE);
- calibra_delay(priv);
-
- for (i = 0; i < 7; i++) {
- if (i == 3)
- continue;
-
- get_calibrete_value(priv, chains, i);
- }
- }
- printk(PFX "Clibrate times is %d\n", j);
- print_offsets(priv);
-} /* do_calibration */
-
-void antenna_calibrate(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
- AGNX_TRACE;
-
- agnx_write32(ctl, AGNX_GCR_NLISTANT, 0x3);
- agnx_write32(ctl, AGNX_GCR_NMEASANT, 0x3);
- agnx_write32(ctl, AGNX_GCR_NACTIANT, 0x3);
- agnx_write32(ctl, AGNX_GCR_NCAPTANT, 0x3);
-
- agnx_write32(ctl, AGNX_GCR_ANTCFG, 0x1f);
- agnx_write32(ctl, AGNX_GCR_BOACT, 0x24);
- agnx_write32(ctl, AGNX_GCR_BOINACT, 0x24);
- agnx_write32(ctl, AGNX_GCR_BODYNA, 0x20);
- agnx_write32(ctl, AGNX_GCR_THD0A, 0x64);
- agnx_write32(ctl, AGNX_GCR_THD0AL, 0x64);
- agnx_write32(ctl, AGNX_GCR_THD0B, 0x46);
- agnx_write32(ctl, AGNX_GCR_THD0BTFEST, 0x3c);
- agnx_write32(ctl, AGNX_GCR_SIGHTH, 0x64);
- agnx_write32(ctl, AGNX_GCR_SIGLTH, 0x30);
-
- spi_rc_write(ctl, RF_CHIP0, 0x20);
- /* Fixme */
- udelay(80);
- /* 1. Should read 0x0 */
- reg = agnx_read32(ctl, AGNX_SPI_RLSW);
- if (0x0 != reg)
- printk(KERN_WARNING PFX "Unmatched rf chips result\n");
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1000);
-
- agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
-
- spi_rc_write(ctl, RF_CHIP0, 0x22);
- udelay(80);
- reg = agnx_read32(ctl, AGNX_SPI_RLSW);
- if (0x0 != reg)
- printk(KERN_WARNING PFX "Unmatched rf chips result\n");
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1005);
-
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x1);
- agnx_write32(ctl, AGNX_GCR_RSTGCTL, 0x0);
-
- reg = agnx_read32(ctl, AGNX_PM_SOFTRST);
- reg |= 0x1c000032;
- agnx_write32(ctl, AGNX_PM_SOFTRST, reg);
- reg = agnx_read32(ctl, AGNX_PM_PLLCTL);
- reg |= 0x0003f07;
- agnx_write32(ctl, AGNX_PM_PLLCTL, reg);
-
- reg = agnx_read32(ctl, 0xec50);
- reg |= 0x40;
- agnx_write32(ctl, 0xec50, reg);
-
- agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0xff8);
- agnx_write32(ctl, AGNX_GCR_DISCOVMOD, 0x3);
-
- agnx_write32(ctl, AGNX_GCR_CHAINNUM, 0x6);
- agnx_write32(ctl, 0x19874, 0x0);
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1700);
-
- /* Calibrate the BaseBandFilter */
- base_band_filter_calibrate(priv);
-
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1002);
-
- agnx_write32(ctl, AGNX_GCR_GAINSET0, 0x1d);
- agnx_write32(ctl, AGNX_GCR_GAINSET1, 0x1d);
- agnx_write32(ctl, AGNX_GCR_GAINSET2, 0x1d);
- agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x1);
-
- agnx_write32(ctl, AGNX_ACI_MODE, 0x1);
- agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);
-
- agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27);
- agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
-
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1400);
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1500);
-
- /* Measure Calibration */
- agnx_write32(ctl, AGNX_ACI_MEASURE, 0x1);
- calibra_delay(priv);
-
- /* do calibration */
- do_calibration(priv);
-
- agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
- agnx_write32(ctl, AGNX_ACI_TIMER1, 0x21);
- agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
- agnx_write32(ctl, AGNX_ACI_LEN, 0xf);
-
- reg = agnx_read32(ctl, AGNX_GCR_GAINSET0);
- reg &= 0xf;
- agnx_write32(ctl, AGNX_GCR_GAINSET0, reg);
- reg = agnx_read32(ctl, AGNX_GCR_GAINSET1);
- reg &= 0xf;
- agnx_write32(ctl, AGNX_GCR_GAINSET1, reg);
- reg = agnx_read32(ctl, AGNX_GCR_GAINSET2);
- reg &= 0xf;
- agnx_write32(ctl, AGNX_GCR_GAINSET2, reg);
-
- agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x0);
- disable_receiver(priv);
-} /* antenna_calibrate */
-
-void __antenna_calibrate(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
-
- /* Calibrate the BaseBandFilter */
- /* base_band_filter_calibrate(priv); */
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1002);
-
-
- agnx_write32(ctl, AGNX_GCR_GAINSET0, 0x1d);
- agnx_write32(ctl, AGNX_GCR_GAINSET1, 0x1d);
- agnx_write32(ctl, AGNX_GCR_GAINSET2, 0x1d);
-
- agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x1);
-
- agnx_write32(ctl, AGNX_ACI_MODE, 0x1);
- agnx_write32(ctl, AGNX_ACI_LEN, 0x3ff);
-
-
- agnx_write32(ctl, AGNX_ACI_TIMER1, 0x27);
- agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1400);
- spi_rf_write(ctl, RF_CHIP0|RF_CHIP1|RF_CHIP2, 0x1500);
- /* Measure Calibration */
- agnx_write32(ctl, AGNX_ACI_MEASURE, 0x1);
- calibra_delay(priv);
- do_calibration(priv);
- agnx_write32(ctl, AGNX_GCR_RXOVERIDE, 0x0);
-
- agnx_write32(ctl, AGNX_ACI_TIMER1, 0x21);
- agnx_write32(ctl, AGNX_ACI_TIMER2, 0x27);
-
- agnx_write32(ctl, AGNX_ACI_LEN, 0xf);
-
- reg = agnx_read32(ctl, AGNX_GCR_GAINSET0);
- reg &= 0xf;
- agnx_write32(ctl, AGNX_GCR_GAINSET0, reg);
- reg = agnx_read32(ctl, AGNX_GCR_GAINSET1);
- reg &= 0xf;
- agnx_write32(ctl, AGNX_GCR_GAINSET1, reg);
- reg = agnx_read32(ctl, AGNX_GCR_GAINSET2);
- reg &= 0xf;
- agnx_write32(ctl, AGNX_GCR_GAINSET2, reg);
-
-
- agnx_write32(ctl, AGNX_GCR_GAINSETWRITE, 0x0);
-
- /* Write 0x3 Gain Control Discovery Mode */
- enable_receiver(priv);
-}
-
-int agnx_set_channel(struct agnx_priv *priv, unsigned int channel)
-{
- AGNX_TRACE;
-
- printk(KERN_ERR PFX "Channel is %d %s\n", channel, __func__);
- radio_channel_set(priv, channel);
- return 0;
-}
diff --git a/drivers/staging/agnx/sta.c b/drivers/staging/agnx/sta.c
deleted file mode 100644
index 3e7db5e2811a..000000000000
--- a/drivers/staging/agnx/sta.c
+++ /dev/null
@@ -1,218 +0,0 @@
-#include <linux/delay.h>
-#include <linux/etherdevice.h>
-#include "phy.h"
-#include "sta.h"
-#include "debug.h"
-
-void hash_read(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id)
-{
- void __iomem *ctl = priv->ctl;
-
- reglo &= 0xFFFF;
- reglo |= 0x30000000;
- reglo |= 0x40000000; /* Set status busy */
- reglo |= sta_id << 16;
-
- iowrite32(0, ctl + AGNX_RXM_HASH_CMD_FLAG);
- iowrite32(reghi, ctl + AGNX_RXM_HASH_CMD_HIGH);
- iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
-
- reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
- reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
- printk(PFX "RX hash cmd are : %.8x%.8x\n", reghi, reglo);
-}
-
-void hash_write(struct agnx_priv *priv, const u8 *mac_addr, u8 sta_id)
-{
- void __iomem *ctl = priv->ctl;
- u32 reghi, reglo;
-
- if (!is_valid_ether_addr(mac_addr))
- printk(KERN_WARNING PFX "Update hash table: Invalid hwaddr!\n");
-
- reghi = mac_addr[0] << 24 | mac_addr[1] << 16 | mac_addr[2] << 8 | mac_addr[3];
- reglo = mac_addr[4] << 8 | mac_addr[5];
- reglo |= 0x10000000; /* Set hash commmand */
- reglo |= 0x40000000; /* Set status busy */
- reglo |= sta_id << 16;
-
- iowrite32(0, ctl + AGNX_RXM_HASH_CMD_FLAG);
- iowrite32(reghi, ctl + AGNX_RXM_HASH_CMD_HIGH);
- iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
-
- reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
- if (!(reglo & 0x80000000))
- printk(KERN_WARNING PFX "Update hash table failed\n");
-}
-
-void hash_delete(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id)
-{
- void __iomem *ctl = priv->ctl;
-
- reglo &= 0xFFFF;
- reglo |= 0x20000000;
- reglo |= 0x40000000; /* Set status busy */
- reglo |= sta_id << 16;
-
- iowrite32(0, ctl + AGNX_RXM_HASH_CMD_FLAG);
- iowrite32(reghi, ctl + AGNX_RXM_HASH_CMD_HIGH);
- iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
- reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
-
- reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
- printk(PFX "RX hash cmd are : %.8x%.8x\n", reghi, reglo);
-
-}
-
-void hash_dump(struct agnx_priv *priv, u8 sta_id)
-{
- void __iomem *ctl = priv->ctl;
- u32 reghi, reglo;
-
- reglo = 0x40000000; /* status bit */
- iowrite32(reglo, ctl + AGNX_RXM_HASH_CMD_LOW);
- iowrite32(sta_id << 16, ctl + AGNX_RXM_HASH_DUMP_DATA);
-
- udelay(80);
-
- reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_HIGH);
- reglo = ioread32(ctl + AGNX_RXM_HASH_CMD_LOW);
- printk(PFX "hash cmd are : %.8x%.8x\n", reghi, reglo);
- reghi = ioread32(ctl + AGNX_RXM_HASH_CMD_FLAG);
- printk(PFX "hash flag is : %.8x\n", reghi);
- reghi = ioread32(ctl + AGNX_RXM_HASH_DUMP_MST);
- reglo = ioread32(ctl + AGNX_RXM_HASH_DUMP_LST);
- printk(PFX "hash dump mst lst: %.8x%.8x\n", reghi, reglo);
- reghi = ioread32(ctl + AGNX_RXM_HASH_DUMP_DATA);
- printk(PFX "hash dump data: %.8x\n", reghi);
-}
-
-void get_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int sta_idx)
-{
- void __iomem *ctl = priv->ctl;
- memcpy_fromio(power, ctl + AGNX_TXM_STAPOWTEMP + sizeof(*power) * sta_idx,
- sizeof(*power));
-}
-
-inline void
-set_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int sta_idx)
-{
- void __iomem *ctl = priv->ctl;
- /* FIXME 2. Write Template to offset + station number */
- memcpy_toio(ctl + AGNX_TXM_STAPOWTEMP + sizeof(*power) * sta_idx,
- power, sizeof(*power));
-}
-
-
-void get_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq,
- unsigned int sta_idx, unsigned int wq_idx)
-{
- void __iomem *data = priv->data;
- memcpy_fromio(tx_wq, data + AGNX_PDU_TX_WQ + sizeof(*tx_wq) * STA_TX_WQ_NUM * sta_idx +
- sizeof(*tx_wq) * wq_idx, sizeof(*tx_wq));
-
-}
-
-inline void set_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq,
- unsigned int sta_idx, unsigned int wq_idx)
-{
- void __iomem *data = priv->data;
- memcpy_toio(data + AGNX_PDU_TX_WQ + sizeof(*tx_wq) * STA_TX_WQ_NUM * sta_idx +
- sizeof(*tx_wq) * wq_idx, tx_wq, sizeof(*tx_wq));
-}
-
-
-void get_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx)
-{
- void __iomem *data = priv->data;
-
- memcpy_fromio(sta, data + AGNX_PDUPOOL + sizeof(*sta) * sta_idx,
- sizeof(*sta));
-}
-
-inline void set_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx)
-{
- void __iomem *data = priv->data;
-
- memcpy_toio(data + AGNX_PDUPOOL + sizeof(*sta) * sta_idx,
- sta, sizeof(*sta));
-}
-
-/* FIXME */
-void sta_power_init(struct agnx_priv *priv, unsigned int sta_idx)
-{
- struct agnx_sta_power power;
- u32 reg;
- AGNX_TRACE;
-
- memset(&power, 0, sizeof(power));
- reg = agnx_set_bits(EDCF, EDCF_SHIFT, 0x1);
- power.reg = cpu_to_le32(reg);
- set_sta_power(priv, &power, sta_idx);
- udelay(40);
-} /* add_power_template */
-
-
-/* @num: The #number of station that is visible to the card */
-static void sta_tx_workqueue_init(struct agnx_priv *priv, unsigned int sta_idx)
-{
- struct agnx_sta_tx_wq tx_wq;
- u32 reg;
- unsigned int i;
-
- memset(&tx_wq, 0, sizeof(tx_wq));
-
- reg = agnx_set_bits(WORK_QUEUE_VALID, WORK_QUEUE_VALID_SHIFT, 1);
- reg |= agnx_set_bits(WORK_QUEUE_ACK_TYPE, WORK_QUEUE_ACK_TYPE_SHIFT, 1);
-/* reg |= agnx_set_bits(WORK_QUEUE_ACK_TYPE, WORK_QUEUE_ACK_TYPE_SHIFT, 0); */
- tx_wq.reg2 |= cpu_to_le32(reg);
-
- /* Suppose all 8 traffic class are used */
- for (i = 0; i < STA_TX_WQ_NUM; i++)
- set_sta_tx_wq(priv, &tx_wq, sta_idx, i);
-} /* sta_tx_workqueue_init */
-
-
-static void sta_traffic_init(struct agnx_sta_traffic *traffic)
-{
- u32 reg;
- memset(traffic, 0, sizeof(*traffic));
-
- reg = agnx_set_bits(NEW_PACKET, NEW_PACKET_SHIFT, 1);
- reg |= agnx_set_bits(TRAFFIC_VALID, TRAFFIC_VALID_SHIFT, 1);
-/* reg |= agnx_set_bits(TRAFFIC_ACK_TYPE, TRAFFIC_ACK_TYPE_SHIFT, 1); */
- traffic->reg0 = cpu_to_le32(reg);
-
- /* 3. setting RX Sequence Number to 4095 */
- reg = agnx_set_bits(RX_SEQUENCE_NUM, RX_SEQUENCE_NUM_SHIFT, 4095);
- traffic->reg1 = cpu_to_le32(reg);
-}
-
-
-/* @num: The #number of station that is visible to the card */
-void sta_init(struct agnx_priv *priv, unsigned int sta_idx)
-{
- /* FIXME the length of sta is 256 bytes Is that
- * dangerous to stack overflow? */
- struct agnx_sta sta;
- u32 reg;
- int i;
-
- memset(&sta, 0, sizeof(sta));
- /* Set valid to 1 */
- reg = agnx_set_bits(STATION_VALID, STATION_VALID_SHIFT, 1);
- /* Set Enable Concatenation to 0 (?) */
- reg |= agnx_set_bits(ENABLE_CONCATENATION, ENABLE_CONCATENATION_SHIFT, 0);
- /* Set Enable Decompression to 0 (?) */
- reg |= agnx_set_bits(ENABLE_DECOMPRESSION, ENABLE_DECOMPRESSION_SHIFT, 0);
- sta.reg = cpu_to_le32(reg);
-
- /* Initialize each of the Traffic Class Structures by: */
- for (i = 0; i < 8; i++)
- sta_traffic_init(sta.traffic + i);
-
- set_sta(priv, &sta, sta_idx);
- sta_tx_workqueue_init(priv, sta_idx);
-} /* sta_descriptor_init */
-
-
diff --git a/drivers/staging/agnx/sta.h b/drivers/staging/agnx/sta.h
deleted file mode 100644
index fd504e3f3870..000000000000
--- a/drivers/staging/agnx/sta.h
+++ /dev/null
@@ -1,222 +0,0 @@
-#ifndef AGNX_STA_H_
-#define AGNX_STA_H_
-
-#define STA_TX_WQ_NUM 8 /* The number of TX workqueue one STA has */
-
-struct agnx_hash_cmd {
- __be32 cmdhi;
-#define MACLO 0xFFFF0000
-#define MACLO_SHIFT 16
-#define STA_ID 0x0000FFF0
-#define STA_ID_SHIFT 4
-#define CMD 0x0000000C
-#define CMD_SHIFT 2
-#define STATUS 0x00000002
-#define STATUS_SHIFT 1
-#define PASS 0x00000001
-#define PASS_SHIFT 1
- __be32 cmdlo;
-} __attribute__((__packed__));
-
-
-/*
- * Station Power Template
- * FIXME Just for agn100 yet
- */
-struct agnx_sta_power {
- __le32 reg;
-#define SIGNAL 0x000000FF /* signal */
-#define SIGNAL_SHIFT 0
-#define RATE 0x00000F00
-#define RATE_SHIFT 8
-#define TIFS 0x00001000
-#define TIFS_SHIFT 12
-#define EDCF 0x00002000
-#define EDCF_SHIFT 13
-#define CHANNEL_BOND 0x00004000
-#define CHANNEL_BOND_SHIFT 14
-#define PHY_MODE 0x00038000
-#define PHY_MODE_SHIFT 15
-#define POWER_LEVEL 0x007C0000
-#define POWER_LEVEL_SHIFT 18
-#define NUM_TRANSMITTERS 0x00800000
-#define NUM_TRANSMITTERS_SHIFT 23
-} __attribute__((__packed__));
-
-/*
- * TX Workqueue Descriptor
- */
-struct agnx_sta_tx_wq {
- __le32 reg0;
-#define HEAD_POINTER_LOW 0xFF000000 /* Head pointer low */
-#define HEAD_POINTER_LOW_SHIFT 24
-#define TAIL_POINTER 0x00FFFFFF /* Tail pointer */
-#define TAIL_POINTER_SHIFT 0
-
- __le32 reg3;
-#define ACK_POINTER_LOW 0xFFFF0000 /* ACK pointer low */
-#define ACK_POINTER_LOW_SHIFT 16
-#define HEAD_POINTER_HIGH 0x0000FFFF /* Head pointer high */
-#define HEAD_POINTER_HIGH_SHIFT 0
-
- __le32 reg1;
-/* ACK timeout tail packet count */
-#define ACK_TIMOUT_TAIL_PACK_CNT 0xFFF00000
-#define ACK_TIMOUT_TAIL_PACK_CNT_SHIFT 20
-/* Head timeout tail packet count */
-#define HEAD_TIMOUT_TAIL_PACK_CNT 0x000FFF00
-#define HEAD_TIMOUT_TAIL_PACK_CNT_SHIFT 8
-#define ACK_POINTER_HIGH 0x000000FF /* ACK pointer high */
-#define ACK_POINTER_HIGH_SHIFT 0
-
- __le32 reg2;
-#define WORK_QUEUE_VALID 0x80000000 /* valid */
-#define WORK_QUEUE_VALID_SHIFT 31
-#define WORK_QUEUE_ACK_TYPE 0x40000000 /* ACK type */
-#define WORK_QUEUE_ACK_TYPE_SHIFT 30
-/* Head timeout window limit fragmentation count */
-#define HEAD_TIMOUT_WIN_LIM_FRAG_CNT 0x3FFF0000
-#define HEAD_TIMOUT_WIN_LIM_FRAG_CNT_SHIFT 16
-/* Head timeout window limit byte count */
-#define HEAD_TIMOUT_WIN_LIM_BYTE_CNT 0x0000FFFF
-#define HEAD_TIMOUT_WIN_LIM_BYTE_CNT_SHIFT 0
-} __attribute__((__packed__));
-
-
-/*
- * Traffic Class Structure
- */
-struct agnx_sta_traffic {
- __le32 reg0;
-#define ACK_TIMOUT_CNT 0xFF800000 /* ACK Timeout Counts */
-#define ACK_TIMOUT_CNT_SHIFT 23
-#define TRAFFIC_ACK_TYPE 0x00600000 /* ACK Type */
-#define TRAFFIC_ACK_TYPE_SHIFT 21
-#define NEW_PACKET 0x00100000 /* New Packet */
-#define NEW_PACKET_SHIFT 20
-#define TRAFFIC_VALID 0x00080000 /* Valid */
-#define TRAFFIC_VALID_SHIFT 19
-#define RX_HDR_DESC_POINTER 0x0007FFFF /* RX Header Descripter pointer */
-#define RX_HDR_DESC_POINTER_SHIFT 0
-
- __le32 reg1;
-#define RX_PACKET_TIMESTAMP 0xFFFF0000 /* RX Packet Timestamp */
-#define RX_PACKET_TIMESTAMP_SHIFT 16
-#define TRAFFIC_RESERVED 0x0000E000 /* Reserved */
-#define TRAFFIC_RESERVED_SHIFT 13
-#define SV 0x00001000 /* sv */
-#define SV_SHIFT 12
-#define RX_SEQUENCE_NUM 0x00000FFF /* RX Sequence Number */
-#define RX_SEQUENCE_NUM_SHIFT 0
-
- __le32 tx_replay_cnt_low; /* TX Replay Counter Low */
-
- __le16 tx_replay_cnt_high; /* TX Replay Counter High */
- __le16 rx_replay_cnt_high; /* RX Replay Counter High */
-
- __be32 rx_replay_cnt_low; /* RX Replay Counter Low */
-} __attribute__((__packed__));
-
-/*
- * Station Descriptors
- */
-struct agnx_sta {
- __le32 tx_session_keys[4]; /* Transmit Session Key (0-3) */
- __le32 rx_session_keys[4]; /* Receive Session Key (0-3) */
-
- __le32 reg;
-#define ID_1 0xC0000000 /* id 1 */
-#define ID_1_SHIFT 30
-#define ID_0 0x30000000 /* id 0 */
-#define ID_0_SHIFT 28
-#define ENABLE_CONCATENATION 0x0FF00000 /* Enable concatenation */
-#define ENABLE_CONCATENATION_SHIFT 20
-#define ENABLE_DECOMPRESSION 0x000FF000 /* Enable decompression */
-#define ENABLE_DECOMPRESSION_SHIFT 12
-#define STA_RESERVED 0x00000C00 /* Reserved */
-#define STA_RESERVED_SHIFT 10
-#define EAP 0x00000200 /* EAP */
-#define EAP_SHIFT 9
-#define ED_NULL 0x00000100 /* ED NULL */
-#define ED_NULL_SHIFT 8
-#define ENCRYPTION_POLICY 0x000000E0 /* Encryption Policy */
-#define ENCRYPTION_POLICY_SHIFT 5
-#define DEFINED_KEY_ID 0x00000018 /* Defined Key ID */
-#define DEFINED_KEY_ID_SHIFT 3
-#define FIXED_KEY 0x00000004 /* Fixed Key */
-#define FIXED_KEY_SHIFT 2
-#define KEY_VALID 0x00000002 /* Key Valid */
-#define KEY_VALID_SHIFT 1
-#define STATION_VALID 0x00000001 /* Station Valid */
-#define STATION_VALID_SHIFT 0
-
- __le32 tx_aes_blks_unicast; /* TX AES Blks Unicast */
- __le32 rx_aes_blks_unicast; /* RX AES Blks Unicast */
-
- __le16 aes_format_err_unicast_cnt; /* AES Format Error Unicast Counts */
- __le16 aes_replay_unicast; /* AES Replay Unicast */
-
- __le16 aes_decrypt_err_unicast; /* AES Decrypt Error Unicast */
- __le16 aes_decrypt_err_default; /* AES Decrypt Error default */
-
- __le16 single_retry_packets; /* Single Retry Packets */
- __le16 failed_tx_packets; /* Failed Tx Packets */
-
- __le16 muti_retry_packets; /* Multiple Retry Packets */
- __le16 ack_timeouts; /* ACK Timeouts */
-
- __le16 frag_tx_cnt; /* Fragment TX Counts */
- __le16 rts_brq_sent; /* RTS Brq Sent */
-
- __le16 tx_packets; /* TX Packets */
- __le16 cts_back_timeout; /* CTS Back Timeout */
-
- __le32 phy_stats_high; /* PHY Stats High */
- __le32 phy_stats_low; /* PHY Stats Low */
-
- struct agnx_sta_traffic traffic[8]; /* Traffic Class Structure (8) */
-
- __le16 traffic_class0_frag_success; /* Traffic Class 0 Fragment Success */
- __le16 traffic_class1_frag_success; /* Traffic Class 1 Fragment Success */
- __le16 traffic_class2_frag_success; /* Traffic Class 2 Fragment Success */
- __le16 traffic_class3_frag_success; /* Traffic Class 3 Fragment Success */
- __le16 traffic_class4_frag_success; /* Traffic Class 4 Fragment Success */
- __le16 traffic_class5_frag_success; /* Traffic Class 5 Fragment Success */
- __le16 traffic_class6_frag_success; /* Traffic Class 6 Fragment Success */
- __le16 traffic_class7_frag_success; /* Traffic Class 7 Fragment Success */
-
- __le16 num_frag_non_prime_rates; /* number of Fragments for non-prime rates */
- __le16 ack_timeout_non_prime_rates; /* ACK Timeout for non-prime rates */
-
-} __attribute__((__packed__));
-
-
-struct agnx_beacon_hdr {
- struct agnx_sta_power power; /* Tx Station Power Template */
- u8 phy_hdr[6]; /* PHY Hdr */
- u8 frame_len_lo; /* Frame Length Lo */
- u8 frame_len_hi; /* Frame Length Hi */
- u8 mac_hdr[24]; /* MAC Header */
- /* FIXME */
- /* 802.11(abg) beacon */
-} __attribute__((__packed__));
-
-void hash_write(struct agnx_priv *priv, const u8 *mac_addr, u8 sta_id);
-void hash_dump(struct agnx_priv *priv, u8 sta_id);
-void hash_read(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id);
-void hash_delete(struct agnx_priv *priv, u32 reghi, u32 reglo, u8 sta_id);
-
-void get_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power, unsigned int sta_idx);
-void set_sta_power(struct agnx_priv *priv, struct agnx_sta_power *power,
- unsigned int sta_idx);
-void get_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq,
- unsigned int sta_idx, unsigned int wq_idx);
-void set_sta_tx_wq(struct agnx_priv *priv, struct agnx_sta_tx_wq *tx_wq,
- unsigned int sta_idx, unsigned int wq_idx);
-void get_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx);
-void set_sta(struct agnx_priv *priv, struct agnx_sta *sta, unsigned int sta_idx);
-
-void sta_power_init(struct agnx_priv *priv, unsigned int num);
-void sta_init(struct agnx_priv *priv, unsigned int num);
-
-#endif /* AGNX_STA_H_ */
diff --git a/drivers/staging/agnx/table.c b/drivers/staging/agnx/table.c
deleted file mode 100644
index b52fef9db0e3..000000000000
--- a/drivers/staging/agnx/table.c
+++ /dev/null
@@ -1,168 +0,0 @@
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include "agnx.h"
-#include "debug.h"
-#include "phy.h"
-
-static const u32
-tx_fir_table[] = { 0x19, 0x5d, 0xce, 0x151, 0x1c3, 0x1ff, 0x1ea, 0x17c, 0xcf,
- 0x19, 0x38e, 0x350, 0x362, 0x3ad, 0x5, 0x44, 0x59, 0x49,
- 0x21, 0x3f7, 0x3e0, 0x3e3, 0x3f3, 0x0 };
-
-void tx_fir_table_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(tx_fir_table); i++)
- iowrite32(tx_fir_table[i], ctl + AGNX_FIR_BASE + i*4);
-} /* fir_table_setup */
-
-
-static const u32
-gain_table[] = { 0x8, 0x8, 0xf, 0x13, 0x17, 0x1b, 0x1f, 0x23, 0x27, 0x2b,
- 0x2f, 0x33, 0x37, 0x3b, 0x3f, 0x43, 0x47, 0x4b, 0x4f,
- 0x53, 0x57, 0x5b, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
- 0x5f, 0x5f, 0x5f, 0x5f };
-
-void gain_table_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(gain_table); i++) {
- iowrite32(gain_table[i], ctl + AGNX_GAIN_TABLE + i*4);
- iowrite32(gain_table[i], ctl + AGNX_GAIN_TABLE + i*4 + 0x80);
- }
-} /* gain_table_init */
-
-void monitor_gain_table_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- unsigned int i;
-
- for (i = 0; i < 0x44; i += 4) {
- iowrite32(0x61, ctl + AGNX_MONGCR_BASE + i);
- iowrite32(0x61, ctl + AGNX_MONGCR_BASE + 0x200 + i);
- }
- for (i = 0x44; i < 0x64; i += 4) {
- iowrite32(0x6e, ctl + AGNX_MONGCR_BASE + i);
- iowrite32(0x6e, ctl + AGNX_MONGCR_BASE + 0x200 + i);
- }
- for (i = 0x64; i < 0x94; i += 4) {
- iowrite32(0x7a, ctl + AGNX_MONGCR_BASE + i);
- iowrite32(0x7a, ctl + AGNX_MONGCR_BASE + 0x200 + i);
- }
- for (i = 0x94; i < 0xdc; i += 4) {
- iowrite32(0x87, ctl + AGNX_MONGCR_BASE + i);
- iowrite32(0x87, ctl + AGNX_MONGCR_BASE + 0x200 + i);
- }
- for (i = 0xdc; i < 0x148; i += 4) {
- iowrite32(0x95, ctl + AGNX_MONGCR_BASE + i);
- iowrite32(0x95, ctl + AGNX_MONGCR_BASE + 0x200 + i);
- }
- for (i = 0x148; i < 0x1e8; i += 4) {
- iowrite32(0xa2, ctl + AGNX_MONGCR_BASE + i);
- iowrite32(0xa2, ctl + AGNX_MONGCR_BASE + 0x200 + i);
- }
- for (i = 0x1e8; i <= 0x1fc; i += 4) {
- iowrite32(0xb0, ctl + AGNX_MONGCR_BASE + i);
- iowrite32(0xb0, ctl + AGNX_MONGCR_BASE + 0x200 + i);
- }
-} /* monitor_gain_table_init */
-
-
-void routing_table_init(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- unsigned int type, subtype;
- u32 reg;
-
- disable_receiver(priv);
-
- for (type = 0; type < 0x3; type++) {
- for (subtype = 0; subtype < 0x10; subtype++) {
- /* 1. Set Routing table to R/W and to Return status on Read */
- reg = (type << ROUTAB_TYPE_SHIFT) |
- (subtype << ROUTAB_SUBTYPE_SHIFT);
- reg |= (1 << ROUTAB_RW_SHIFT) | (1 << ROUTAB_STATUS_SHIFT);
- if (type == ROUTAB_TYPE_DATA) {
- /* NULL goes to RFP */
- if (subtype == ROUTAB_SUBTYPE_NULL)
-/* reg |= ROUTAB_ROUTE_RFP; */
- reg |= ROUTAB_ROUTE_CPU;
- /* QOS NULL goes to CPU */
- else if (subtype == ROUTAB_SUBTYPE_QOSNULL)
- reg |= ROUTAB_ROUTE_CPU;
- /* All Data and QOS data subtypes go to Encryption */
- else if ((subtype == ROUTAB_SUBTYPE_DATA) ||
- (subtype == ROUTAB_SUBTYPE_DATAACK) ||
- (subtype == ROUTAB_SUBTYPE_DATAPOLL) ||
- (subtype == ROUTAB_SUBTYPE_DATAPOLLACK) ||
- (subtype == ROUTAB_SUBTYPE_QOSDATA) ||
- (subtype == ROUTAB_SUBTYPE_QOSDATAACK) ||
- (subtype == ROUTAB_SUBTYPE_QOSDATAPOLL) ||
- (subtype == ROUTAB_SUBTYPE_QOSDATAACKPOLL))
- reg |= ROUTAB_ROUTE_ENCRY;
-/* reg |= ROUTAB_ROUTE_CPU; */
- /*Drop NULL and QOS NULL ack, poll and poll ack*/
- else if ((subtype == ROUTAB_SUBTYPE_NULLACK) ||
- (subtype == ROUTAB_SUBTYPE_QOSNULLACK) ||
- (subtype == ROUTAB_SUBTYPE_NULLPOLL) ||
- (subtype == ROUTAB_SUBTYPE_QOSNULLPOLL) ||
- (subtype == ROUTAB_SUBTYPE_NULLPOLLACK) ||
- (subtype == ROUTAB_SUBTYPE_QOSNULLPOLLACK))
-/* reg |= ROUTAB_ROUTE_DROP; */
- reg |= ROUTAB_ROUTE_CPU;
- } else {
- reg |= (ROUTAB_ROUTE_CPU);
- }
- iowrite32(reg, ctl + AGNX_RXM_ROUTAB);
- /* Check to verify that the status bit cleared */
- routing_table_delay();
- }
- }
- enable_receiver(priv);
-} /* routing_table_init */
-
-void tx_engine_lookup_tbl_init(struct agnx_priv *priv)
-{
- void __iomem *data = priv->data;
- unsigned int i;
-
- for (i = 0; i <= 28; i += 4)
- iowrite32(0xb00c, data + AGNX_ENGINE_LOOKUP_TBL + i);
- for (i = 32; i <= 120; i += 8) {
- iowrite32(0x1e58, data + AGNX_ENGINE_LOOKUP_TBL + i);
- iowrite32(0xb00c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4);
- }
-
- for (i = 128; i <= 156; i += 4)
- iowrite32(0x980c, data + AGNX_ENGINE_LOOKUP_TBL + i);
- for (i = 160; i <= 248; i += 8) {
- iowrite32(0x1858, data + AGNX_ENGINE_LOOKUP_TBL + i);
- iowrite32(0x980c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4);
- }
-
- for (i = 256; i <= 284; i += 4)
- iowrite32(0x980c, data + AGNX_ENGINE_LOOKUP_TBL + i);
- for (i = 288; i <= 376; i += 8) {
- iowrite32(0x1a58, data + AGNX_ENGINE_LOOKUP_TBL + i);
- iowrite32(0x1858, data + AGNX_ENGINE_LOOKUP_TBL + i + 4);
- }
-
- for (i = 512; i <= 540; i += 4)
- iowrite32(0xc00c, data + AGNX_ENGINE_LOOKUP_TBL + i);
- for (i = 544; i <= 632; i += 8) {
- iowrite32(0x2058, data + AGNX_ENGINE_LOOKUP_TBL + i);
- iowrite32(0xc00c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4);
- }
-
- for (i = 640; i <= 668; i += 4)
- iowrite32(0xc80c, data + AGNX_ENGINE_LOOKUP_TBL + i);
- for (i = 672; i <= 764; i += 8) {
- iowrite32(0x2258, data + AGNX_ENGINE_LOOKUP_TBL + i);
- iowrite32(0xc80c, data + AGNX_ENGINE_LOOKUP_TBL + i + 4);
- }
-}
-
diff --git a/drivers/staging/agnx/table.h b/drivers/staging/agnx/table.h
deleted file mode 100644
index f0626b5ee86b..000000000000
--- a/drivers/staging/agnx/table.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef AGNX_TABLE_H_
-#define AGNX_TABLE_H_
-
-void tx_fir_table_init(struct agnx_priv *priv);
-void gain_table_init(struct agnx_priv *priv);
-void monitor_gain_table_init(struct agnx_priv *priv);
-void routing_table_init(struct agnx_priv *priv);
-void tx_engine_lookup_tbl_init(struct agnx_priv *priv);
-
-#endif /* AGNX_TABLE_H_ */
diff --git a/drivers/staging/agnx/xmit.c b/drivers/staging/agnx/xmit.c
deleted file mode 100644
index 42db41070cf0..000000000000
--- a/drivers/staging/agnx/xmit.c
+++ /dev/null
@@ -1,836 +0,0 @@
-/**
- * Airgo MIMO wireless driver
- *
- * Copyright (c) 2007 Li YanBo <dreamfly281@gmail.com>
-
- * Thanks for Jeff Williams <angelbane@gmail.com> do reverse engineer
- * works and published the SPECS at http://airgo.wdwconsulting.net/mymoin
-
- * 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/pci.h>
-#include <linux/delay.h>
-#include "agnx.h"
-#include "debug.h"
-#include "phy.h"
-
-unsigned int rx_frame_cnt;
-/* unsigned int local_tx_sent_cnt = 0; */
-
-static inline void disable_rx_engine(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- iowrite32(0x100, ctl + AGNX_CIR_RXCTL);
- /* Wait for RX Control to have the Disable Rx Interrupt (0x100) set */
- ioread32(ctl + AGNX_CIR_RXCTL);
-}
-
-static inline void enable_rx_engine(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- iowrite32(0x80, ctl + AGNX_CIR_RXCTL);
- ioread32(ctl + AGNX_CIR_RXCTL);
-}
-
-inline void disable_rx_interrupt(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
-
- disable_rx_engine(priv);
- reg = ioread32(ctl + AGNX_CIR_RXCFG);
- reg &= ~0x20;
- iowrite32(reg, ctl + AGNX_CIR_RXCFG);
- ioread32(ctl + AGNX_CIR_RXCFG);
-}
-
-inline void enable_rx_interrupt(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- u32 reg;
-
- reg = ioread32(ctl + AGNX_CIR_RXCFG);
- reg |= 0x20;
- iowrite32(reg, ctl + AGNX_CIR_RXCFG);
- ioread32(ctl + AGNX_CIR_RXCFG);
- enable_rx_engine(priv);
-}
-
-static inline void rx_desc_init(struct agnx_priv *priv, unsigned int idx)
-{
- struct agnx_desc *desc = priv->rx.desc + idx;
- struct agnx_info *info = priv->rx.info + idx;
-
- memset(info, 0, sizeof(*info));
-
- info->dma_len = IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct agnx_hdr);
- info->skb = dev_alloc_skb(info->dma_len);
- if (info->skb == NULL)
- agnx_bug("refill err");
-
- info->mapping = pci_map_single(priv->pdev, skb_tail_pointer(info->skb),
- info->dma_len, PCI_DMA_FROMDEVICE);
- memset(desc, 0, sizeof(*desc));
- desc->dma_addr = cpu_to_be32(info->mapping);
- /* Set the owner to the card */
- desc->frag = cpu_to_be32(be32_to_cpu(desc->frag) | OWNER);
-}
-
-static inline void rx_desc_reinit(struct agnx_priv *priv, unsigned int idx)
-{
- struct agnx_info *info = priv->rx.info + idx;
-
- /* Cause ieee80211 will free the skb buffer, so we needn't to free it again?! */
- pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_FROMDEVICE);
- rx_desc_init(priv, idx);
-}
-
-static inline void rx_desc_reusing(struct agnx_priv *priv, unsigned int idx)
-{
- struct agnx_desc *desc = priv->rx.desc + idx;
- struct agnx_info *info = priv->rx.info + idx;
-
- memset(desc, 0, sizeof(*desc));
- desc->dma_addr = cpu_to_be32(info->mapping);
- /* Set the owner to the card */
- desc->frag = cpu_to_be32(be32_to_cpu(desc->frag) | OWNER);
-}
-
-static void rx_desc_free(struct agnx_priv *priv, unsigned int idx)
-{
- struct agnx_desc *desc = priv->rx.desc + idx;
- struct agnx_info *info = priv->rx.info + idx;
-
- BUG_ON(!desc || !info);
- if (info->mapping)
- pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_FROMDEVICE);
- if (info->skb)
- dev_kfree_skb(info->skb);
- memset(info, 0, sizeof(*info));
- memset(desc, 0, sizeof(*desc));
-}
-
-static inline void __tx_desc_free(struct agnx_priv *priv,
- struct agnx_desc *desc, struct agnx_info *info)
-{
- BUG_ON(!desc || !info);
- /* TODO make sure mapping, skb and len are consistency */
- if (info->mapping)
- pci_unmap_single(priv->pdev, info->mapping,
- info->dma_len, PCI_DMA_TODEVICE);
- if (info->type == PACKET)
- dev_kfree_skb(info->skb);
-
- memset(info, 0, sizeof(*info));
- memset(desc, 0, sizeof(*desc));
-}
-
-static void txm_desc_free(struct agnx_priv *priv, unsigned int idx)
-{
- struct agnx_desc *desc = priv->txm.desc + idx;
- struct agnx_info *info = priv->txm.info + idx;
-
- __tx_desc_free(priv, desc, info);
-}
-
-static void txd_desc_free(struct agnx_priv *priv, unsigned int idx)
-{
- struct agnx_desc *desc = priv->txd.desc + idx;
- struct agnx_info *info = priv->txd.info + idx;
-
- __tx_desc_free(priv, desc, info);
-}
-
-int fill_rings(struct agnx_priv *priv)
-{
- void __iomem *ctl = priv->ctl;
- unsigned int i;
- u32 reg;
- AGNX_TRACE;
-
- priv->txd.idx_sent = priv->txm.idx_sent = 0;
- priv->rx.idx = priv->txm.idx = priv->txd.idx = 0;
-
- for (i = 0; i < priv->rx.size; i++)
- rx_desc_init(priv, i);
- for (i = 0; i < priv->txm.size; i++) {
- memset(priv->txm.desc + i, 0, sizeof(struct agnx_desc));
- memset(priv->txm.info + i, 0, sizeof(struct agnx_info));
- }
- for (i = 0; i < priv->txd.size; i++) {
- memset(priv->txd.desc + i, 0, sizeof(struct agnx_desc));
- memset(priv->txd.info + i, 0, sizeof(struct agnx_info));
- }
-
- /* FIXME Set the card RX TXM and TXD address */
- agnx_write32(ctl, AGNX_CIR_RXCMSTART, priv->rx.dma);
- agnx_write32(ctl, AGNX_CIR_RXCMEND, priv->txm.dma);
-
- agnx_write32(ctl, AGNX_CIR_TXMSTART, priv->txm.dma);
- agnx_write32(ctl, AGNX_CIR_TXMEND, priv->txd.dma);
-
- agnx_write32(ctl, AGNX_CIR_TXDSTART, priv->txd.dma);
- agnx_write32(ctl, AGNX_CIR_TXDEND, priv->txd.dma +
- sizeof(struct agnx_desc) * priv->txd.size);
-
- /* FIXME Relinquish control of rings to card */
- reg = agnx_read32(ctl, AGNX_CIR_BLKCTL);
- reg &= ~0x800;
- agnx_write32(ctl, AGNX_CIR_BLKCTL, reg);
- return 0;
-} /* fill_rings */
-
-void unfill_rings(struct agnx_priv *priv)
-{
- unsigned long flags;
- unsigned int i;
- AGNX_TRACE;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- for (i = 0; i < priv->rx.size; i++)
- rx_desc_free(priv, i);
- for (i = 0; i < priv->txm.size; i++)
- txm_desc_free(priv, i);
- for (i = 0; i < priv->txd.size; i++)
- txd_desc_free(priv, i);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/* Extract the bitrate out of a CCK PLCP header.
- copy from bcm43xx driver */
-static inline u8 agnx_plcp_get_bitrate_cck(__be32 *phyhdr_11b)
-{
- /* FIXME */
- switch (*(u8 *)phyhdr_11b) {
- case 0x0A:
- return 0;
- case 0x14:
- return 1;
- case 0x37:
- return 2;
- case 0x6E:
- return 3;
- }
- agnx_bug("Wrong plcp rate");
- return 0;
-}
-
-/* FIXME */
-static inline u8 agnx_plcp_get_bitrate_ofdm(__be32 *phyhdr_11g)
-{
- u8 rate = *(u8 *)phyhdr_11g & 0xF;
-
- printk(PFX "G mode rate is 0x%x\n", rate);
- return rate;
-}
-
-/* FIXME */
-static void get_rx_stats(struct agnx_priv *priv, struct agnx_hdr *hdr,
- struct ieee80211_rx_status *stat)
-{
- void __iomem *ctl = priv->ctl;
- u8 *rssi;
- u32 noise;
- /* FIXME just for test */
- int snr = 40; /* signal-to-noise ratio */
-
- memset(stat, 0, sizeof(*stat));
- /* RSSI */
- rssi = (u8 *)&hdr->phy_stats_lo;
-/* stat->ssi = (rssi[0] + rssi[1] + rssi[2]) / 3; */
- /* Noise */
- noise = ioread32(ctl + AGNX_GCR_NOISE0);
- noise += ioread32(ctl + AGNX_GCR_NOISE1);
- noise += ioread32(ctl + AGNX_GCR_NOISE2);
- stat->noise = noise / 3;
- /* Signal quality */
-/* snr = stat->ssi - stat->noise; */
- if (snr >= 0 && snr < 40)
- stat->signal = 5 * snr / 2;
- else if (snr >= 40)
- stat->signal = 100;
- else
- stat->signal = 0;
-
-
- if (hdr->_11b0 && !hdr->_11g0) {
- stat->rate_idx = agnx_plcp_get_bitrate_cck(&hdr->_11b0);
- } else if (!hdr->_11b0 && hdr->_11g0) {
- printk(PFX "RX: Found G mode packet\n");
- stat->rate_idx = agnx_plcp_get_bitrate_ofdm(&hdr->_11g0);
- } else
- agnx_bug("Unknown packets type");
-
-
- stat->band = IEEE80211_BAND_2GHZ;
- stat->freq = agnx_channels[priv->channel - 1].center_freq;
-/* stat->antenna = 3;
- stat->mactime = be32_to_cpu(hdr->time_stamp);
- stat->channel = priv->channel; */
-}
-
-static inline void combine_hdr_frag(struct ieee80211_hdr *ieeehdr,
- struct sk_buff *skb)
-{
- u16 fctl;
- unsigned int hdrlen;
-
- fctl = le16_to_cpu(ieeehdr->frame_control);
- hdrlen = ieee80211_hdrlen(fctl);
- /* FIXME */
- if (hdrlen < (2+2+6)/*minimum hdr*/ ||
- hdrlen > sizeof(struct ieee80211_mgmt)) {
- printk(KERN_ERR PFX "hdr len is %d\n", hdrlen);
- agnx_bug("Wrong ieee80211 hdr detected");
- }
- skb_push(skb, hdrlen);
- memcpy(skb->data, ieeehdr, hdrlen);
-} /* combine_hdr_frag */
-
-static inline int agnx_packet_check(struct agnx_priv *priv, struct agnx_hdr *agnxhdr,
- unsigned packet_len)
-{
- if (agnx_get_bits(CRC_FAIL, CRC_FAIL_SHIFT, be32_to_cpu(agnxhdr->reg1)) == 1) {
- printk(PFX "RX: CRC check fail\n");
- goto drop;
- }
- if (packet_len > 2048) {
- printk(PFX "RX: Too long packet detected\n");
- goto drop;
- }
-
- /* FIXME Just usable for Promious Mode, for Manage mode exclude FCS */
-/* if (packet_len - sizeof(*agnxhdr) < FCS_LEN) { */
-/* printk(PFX "RX: Too short packet detected\n"); */
-/* goto drop; */
-/* } */
- return 0;
-drop:
- priv->stats.dot11FCSErrorCount++;
- return -1;
-}
-
-void handle_rx_irq(struct agnx_priv *priv)
-{
- struct ieee80211_rx_status status;
- unsigned int len;
-/* AGNX_TRACE; */
-
- do {
- struct agnx_desc *desc;
- u32 frag;
- struct agnx_info *info;
- struct agnx_hdr *hdr;
- struct sk_buff *skb;
- unsigned int i = priv->rx.idx % priv->rx.size;
-
- desc = priv->rx.desc + i;
- frag = be32_to_cpu(desc->frag);
- if (frag & OWNER)
- break;
-
- info = priv->rx.info + i;
- skb = info->skb;
- hdr = (struct agnx_hdr *)(skb->data);
-
- len = (frag & PACKET_LEN) >> PACKET_LEN_SHIFT;
- if (agnx_packet_check(priv, hdr, len) == -1) {
- rx_desc_reusing(priv, i);
- continue;
- }
- skb_put(skb, len);
-
- do {
- u16 fctl;
- fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr)->frame_control);
- if ((fctl & IEEE80211_FCTL_STYPE) != IEEE80211_STYPE_BEACON)/* && !(fctl & IEEE80211_STYPE_BEACON)) */
- dump_ieee80211_hdr((struct ieee80211_hdr *)hdr->mac_hdr, "RX");
- } while (0);
-
- if (hdr->_11b0 && !hdr->_11g0) {
-/* int j;
- u16 fctl = le16_to_cpu(((struct ieee80211_hdr *)hdr->mac_hdr)
- ->frame_control);
- if ( (fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA) {
- agnx_print_rx_hdr(hdr);
- agnx_print_sta(priv, BSSID_STAID);
- for (j = 0; j < 8; j++)
- agnx_print_sta_tx_wq(priv, BSSID_STAID, j);
- } */
-
- get_rx_stats(priv, hdr, &status);
- skb_pull(skb, sizeof(*hdr));
- combine_hdr_frag((struct ieee80211_hdr *)hdr->mac_hdr, skb);
- } else if (!hdr->_11b0 && hdr->_11g0) {
-/* int j; */
- agnx_print_rx_hdr(hdr);
- agnx_print_sta(priv, BSSID_STAID);
-/* for (j = 0; j < 8; j++) */
- agnx_print_sta_tx_wq(priv, BSSID_STAID, 0);
-
- print_hex_dump_bytes("agnx: RX_PACKET: ", DUMP_PREFIX_NONE,
- skb->data, skb->len + 8);
-
-/* if (agnx_plcp_get_bitrate_ofdm(&hdr->_11g0) == 0) */
- get_rx_stats(priv, hdr, &status);
- skb_pull(skb, sizeof(*hdr));
- combine_hdr_frag((struct ieee80211_hdr *)
- ((void *)&hdr->mac_hdr), skb);
-/* dump_ieee80211_hdr((struct ieee80211_hdr *)skb->data, "RX G"); */
- } else
- agnx_bug("Unknown packets type");
- memcpy(IEEE80211_SKB_RXCB(skb), &status, sizeof(status));
- ieee80211_rx_irqsafe(priv->hw, skb);
- rx_desc_reinit(priv, i);
-
- } while (priv->rx.idx++);
-} /* handle_rx_irq */
-
-static inline void handle_tx_irq(struct agnx_priv *priv, struct agnx_ring *ring)
-{
- struct agnx_desc *desc;
- struct agnx_info *info;
- unsigned int idx;
-
- for (idx = ring->idx_sent; idx < ring->idx; idx++) {
- unsigned int i = idx % ring->size;
- u32 frag;
-
- desc = ring->desc + i;
- info = ring->info + i;
-
- frag = be32_to_cpu(desc->frag);
- if (frag & OWNER) {
- if (info->type == HEADER)
- break;
- else
- agnx_bug("TX error");
- }
-
- pci_unmap_single(priv->pdev, info->mapping, info->dma_len, PCI_DMA_TODEVICE);
-
- do {
-/* int j; */
- size_t len;
- len = info->skb->len - sizeof(struct agnx_hdr) + info->hdr_len;
-/* if (len == 614) { */
-/* agnx_print_desc(desc); */
- if (info->type == PACKET) {
-/* agnx_print_tx_hdr((struct agnx_hdr *)info->skb->data); */
-/* agnx_print_sta_power(priv, LOCAL_STAID); */
-/* agnx_print_sta(priv, LOCAL_STAID); */
-/* for (j = 0; j < 8; j++) */
-/* agnx_print_sta_tx_wq(priv, LOCAL_STAID, 0); */
-/* agnx_print_sta_power(priv, BSSID_STAID); */
-/* agnx_print_sta(priv, BSSID_STAID); */
-/* for (j = 0; j < 8; j++) */
-/* agnx_print_sta_tx_wq(priv, BSSID_STAID, 0); */
- }
-/* } */
- } while (0);
-
- if (info->type == PACKET) {
-/* dump_txm_registers(priv);
- dump_rxm_registers(priv);
- dump_bm_registers(priv);
- dump_cir_registers(priv); */
- }
-
- if (info->type == PACKET) {
-/* struct ieee80211_hdr *hdr; */
- struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(info->skb);
-
- skb_pull(info->skb, sizeof(struct agnx_hdr));
- memcpy(skb_push(info->skb, info->hdr_len), &info->hdr, info->hdr_len);
-
-/* dump_ieee80211_hdr((struct ieee80211_hdr *)info->skb->data, "TX_HANDLE"); */
-/* print_hex_dump_bytes("agnx: TX_HANDLE: ", DUMP_PREFIX_NONE, */
-/* info->skb->data, info->skb->len); */
-
- if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK))
- txi->flags |= IEEE80211_TX_STAT_ACK;
-
- ieee80211_tx_status_irqsafe(priv->hw, info->skb);
-
-
-/* info->tx_status.queue_number = (ring->size - i) / 2; */
-/* ieee80211_tx_status_irqsafe(priv->hw, info->skb, &(info->tx_status)); */
-/* } else */
-/* dev_kfree_skb_irq(info->skb); */
- }
- memset(desc, 0, sizeof(*desc));
- memset(info, 0, sizeof(*info));
- }
-
- ring->idx_sent = idx;
- /* TODO fill the priv->low_level_stats */
-
- /* ieee80211_wake_queue(priv->hw, 0); */
-}
-
-void handle_txm_irq(struct agnx_priv *priv)
-{
- handle_tx_irq(priv, &priv->txm);
-}
-
-void handle_txd_irq(struct agnx_priv *priv)
-{
- handle_tx_irq(priv, &priv->txd);
-}
-
-void handle_other_irq(struct agnx_priv *priv)
-{
-/* void __iomem *ctl = priv->ctl; */
- u32 status = priv->irq_status;
- void __iomem *ctl = priv->ctl;
- u32 reg;
-
- if (status & IRQ_TX_BEACON) {
- iowrite32(IRQ_TX_BEACON, ctl + AGNX_INT_STAT);
- printk(PFX "IRQ: TX Beacon control is 0X%.8X\n", ioread32(ctl + AGNX_TXM_BEACON_CTL));
- printk(PFX "IRQ: TX Beacon rx frame num: %d\n", rx_frame_cnt);
- }
- if (status & IRQ_TX_RETRY) {
- reg = ioread32(ctl + AGNX_TXM_RETRYSTAID);
- printk(PFX "IRQ: TX Retry, RETRY STA ID is %x\n", reg);
- }
- if (status & IRQ_TX_ACTIVITY)
- printk(PFX "IRQ: TX Activity\n");
- if (status & IRQ_RX_ACTIVITY)
- printk(PFX "IRQ: RX Activity\n");
- if (status & IRQ_RX_X)
- printk(PFX "IRQ: RX X\n");
- if (status & IRQ_RX_Y) {
- reg = ioread32(ctl + AGNX_INT_MASK);
- reg &= ~IRQ_RX_Y;
- iowrite32(reg, ctl + AGNX_INT_MASK);
- iowrite32(IRQ_RX_Y, ctl + AGNX_INT_STAT);
- printk(PFX "IRQ: RX Y\n");
- }
- if (status & IRQ_RX_HASHHIT) {
- reg = ioread32(ctl + AGNX_INT_MASK);
- reg &= ~IRQ_RX_HASHHIT;
- iowrite32(reg, ctl + AGNX_INT_MASK);
- iowrite32(IRQ_RX_HASHHIT, ctl + AGNX_INT_STAT);
- printk(PFX "IRQ: RX Hash Hit\n");
-
- }
- if (status & IRQ_RX_FRAME) {
- reg = ioread32(ctl + AGNX_INT_MASK);
- reg &= ~IRQ_RX_FRAME;
- iowrite32(reg, ctl + AGNX_INT_MASK);
- iowrite32(IRQ_RX_FRAME, ctl + AGNX_INT_STAT);
- printk(PFX "IRQ: RX Frame\n");
- rx_frame_cnt++;
- }
- if (status & IRQ_ERR_INT) {
- iowrite32(IRQ_ERR_INT, ctl + AGNX_INT_STAT);
-/* agnx_hw_reset(priv); */
- printk(PFX "IRQ: Error Interrupt\n");
- }
- if (status & IRQ_TX_QUE_FULL)
- printk(PFX "IRQ: TX Workqueue Full\n");
- if (status & IRQ_BANDMAN_ERR)
- printk(PFX "IRQ: Bandwidth Management Error\n");
- if (status & IRQ_TX_DISABLE)
- printk(PFX "IRQ: TX Disable\n");
- if (status & IRQ_RX_IVASESKEY)
- printk(PFX "IRQ: RX Invalid Session Key\n");
- if (status & IRQ_REP_THHIT)
- printk(PFX "IRQ: Replay Threshold Hit\n");
- if (status & IRQ_TIMER1)
- printk(PFX "IRQ: Timer1\n");
- if (status & IRQ_TIMER_CNT)
- printk(PFX "IRQ: Timer Count\n");
- if (status & IRQ_PHY_FASTINT)
- printk(PFX "IRQ: Phy Fast Interrupt\n");
- if (status & IRQ_PHY_SLOWINT)
- printk(PFX "IRQ: Phy Slow Interrupt\n");
- if (status & IRQ_OTHER)
- printk(PFX "IRQ: 0x80000000\n");
-} /* handle_other_irq */
-
-
-static inline void route_flag_set(struct agnx_hdr *txhdr)
-{
-/* u32 reg = 0; */
-
- /* FIXME */
-/* reg = (0x7 << ROUTE_COMPRESSION_SHIFT) & ROUTE_COMPRESSION; */
-/* txhdr->reg5 = cpu_to_be32(reg); */
- txhdr->reg5 = (0xa << 0x0) | (0x7 << 0x18);
-/* txhdr->reg5 = cpu_to_be32((0xa << 0x0) | (0x7 << 0x18)); */
-/* txhdr->reg5 = cpu_to_be32(0x7 << 0x0); */
-}
-
-/* Return 0 if no match */
-static inline unsigned int get_power_level(unsigned int rate, unsigned int antennas_num)
-{
- unsigned int power_level;
-
- switch (rate) {
- case 10:
- case 20:
- case 55:
- case 60:
- case 90:
- case 120:
- power_level = 22;
- break;
-
- case 180:
- power_level = 19;
- break;
-
- case 240:
- power_level = 18;
- break;
-
- case 360:
- power_level = 16;
- break;
-
- case 480:
- power_level = 15;
- break;
-
- case 540:
- power_level = 14;
- break;
- default:
- agnx_bug("Error rate setting\n");
- }
-
- if (power_level && (antennas_num == 2))
- power_level -= 3;
-
- return power_level;
-}
-
-static inline void fill_agnx_hdr(struct agnx_priv *priv, struct agnx_info *tx_info)
-{
- struct agnx_hdr *txhdr = (struct agnx_hdr *)tx_info->skb->data;
- size_t len;
- u16 fc = le16_to_cpu(*(__le16 *)&tx_info->hdr);
- u32 reg;
-
- memset(txhdr, 0, sizeof(*txhdr));
-
-/* reg = agnx_set_bits(STATION_ID, STATION_ID_SHIFT, LOCAL_STAID); */
- reg = agnx_set_bits(STATION_ID, STATION_ID_SHIFT, BSSID_STAID);
- reg |= agnx_set_bits(WORKQUEUE_ID, WORKQUEUE_ID_SHIFT, 0);
- txhdr->reg4 = cpu_to_be32(reg);
-
- /* Set the Hardware Sequence Number to 1? */
- reg = agnx_set_bits(SEQUENCE_NUMBER, SEQUENCE_NUMBER_SHIFT, 0);
-/* reg = agnx_set_bits(SEQUENCE_NUMBER, SEQUENCE_NUMBER_SHIFT, 1); */
- reg |= agnx_set_bits(MAC_HDR_LEN, MAC_HDR_LEN_SHIFT, tx_info->hdr_len);
- txhdr->reg1 = cpu_to_be32(reg);
- /* Set the agnx_hdr's MAC header */
- memcpy(txhdr->mac_hdr, &tx_info->hdr, tx_info->hdr_len);
-
- reg = agnx_set_bits(ACK, ACK_SHIFT, 1);
-/* reg = agnx_set_bits(ACK, ACK_SHIFT, 0); */
- reg |= agnx_set_bits(MULTICAST, MULTICAST_SHIFT, 0);
-/* reg |= agnx_set_bits(MULTICAST, MULTICAST_SHIFT, 1); */
- reg |= agnx_set_bits(RELAY, RELAY_SHIFT, 0);
- reg |= agnx_set_bits(TM, TM_SHIFT, 0);
- txhdr->reg0 = cpu_to_be32(reg);
-
- /* Set the long and short retry limits */
- txhdr->tx.short_retry_limit = tx_info->txi->control.rates[0].count;
- txhdr->tx.long_retry_limit = tx_info->txi->control.rates[0].count;
-
- /* FIXME */
- len = tx_info->skb->len - sizeof(*txhdr) + tx_info->hdr_len + FCS_LEN;
- if (fc & IEEE80211_FCTL_PROTECTED)
- len += 8;
- len = 2398;
- reg = agnx_set_bits(FRAG_SIZE, FRAG_SIZE_SHIFT, len);
- len = tx_info->skb->len - sizeof(*txhdr);
- reg |= agnx_set_bits(PAYLOAD_LEN, PAYLOAD_LEN_SHIFT, len);
- txhdr->reg3 = cpu_to_be32(reg);
-
- route_flag_set(txhdr);
-} /* fill_hdr */
-
-static void txm_power_set(struct agnx_priv *priv,
- struct ieee80211_tx_info *txi)
-{
- struct agnx_sta_power power;
- u32 reg;
-
- /* FIXME */
- if (txi->control.rates[0].idx < 0) {
- /* For B mode Short Preamble */
- reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211B_SHORT);
-/* control->tx_rate = -control->tx_rate; */
- } else
- reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211G);
-/* reg = agnx_set_bits(PHY_MODE, PHY_MODE_SHIFT, AGNX_MODE_80211B_LONG); */
- reg |= agnx_set_bits(SIGNAL, SIGNAL_SHIFT, 0xB);
- reg |= agnx_set_bits(RATE, RATE_SHIFT, 0xB);
-/* reg |= agnx_set_bits(POWER_LEVEL, POWER_LEVEL_SHIFT, 15); */
- reg |= agnx_set_bits(POWER_LEVEL, POWER_LEVEL_SHIFT, 20);
- /* if rate < 11M set it to 0 */
- reg |= agnx_set_bits(NUM_TRANSMITTERS, NUM_TRANSMITTERS_SHIFT, 1);
-/* reg |= agnx_set_bits(EDCF, EDCF_SHIFT, 1); */
-/* reg |= agnx_set_bits(TIFS, TIFS_SHIFT, 1); */
-
- power.reg = reg;
-/* power.reg = cpu_to_le32(reg); */
-
-/* set_sta_power(priv, &power, LOCAL_STAID); */
- set_sta_power(priv, &power, BSSID_STAID);
-}
-
-static inline int tx_packet_check(struct sk_buff *skb)
-{
- unsigned int ieee_len = ieee80211_get_hdrlen_from_skb(skb);
- if (skb->len > 2048) {
- printk(KERN_ERR PFX "length is %d\n", skb->len);
- agnx_bug("Too long TX skb");
- return -1;
- }
- /* FIXME */
- if (skb->len == ieee_len) {
- printk(PFX "A strange TX packet\n");
- return -1;
- /* tx_faile_irqsafe(); */
- }
- return 0;
-}
-
-static int __agnx_tx(struct agnx_priv *priv, struct sk_buff *skb,
- struct agnx_ring *ring)
-{
- struct agnx_desc *hdr_desc, *frag_desc;
- struct agnx_info *hdr_info, *frag_info;
- struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
- unsigned long flags;
- unsigned int i;
-
- spin_lock_irqsave(&priv->lock, flags);
-
- /* The RX interrupt need be Disable until this TX packet
- is handled in the next tx interrupt */
- disable_rx_interrupt(priv);
-
- i = ring->idx;
- ring->idx += 2;
-/* if (priv->txm_idx - priv->txm_idx_sent == AGNX_TXM_RING_SIZE - 2) */
-/* ieee80211_stop_queue(priv->hw, 0); */
-
- /* Set agnx header's info and desc */
- i %= ring->size;
- hdr_desc = ring->desc + i;
- hdr_info = ring->info + i;
- hdr_info->hdr_len = ieee80211_get_hdrlen_from_skb(skb);
- memcpy(&hdr_info->hdr, skb->data, hdr_info->hdr_len);
-
- /* Add the agnx header to the front of the SKB */
- skb_push(skb, sizeof(struct agnx_hdr) - hdr_info->hdr_len);
-
- hdr_info->txi = txi;
- hdr_info->dma_len = sizeof(struct agnx_hdr);
- hdr_info->skb = skb;
- hdr_info->type = HEADER;
- fill_agnx_hdr(priv, hdr_info);
- hdr_info->mapping = pci_map_single(priv->pdev, skb->data,
- hdr_info->dma_len, PCI_DMA_TODEVICE);
- do {
- u32 frag = 0;
- frag |= agnx_set_bits(FIRST_FRAG, FIRST_FRAG_SHIFT, 1);
- frag |= agnx_set_bits(LAST_FRAG, LAST_FRAG_SHIFT, 0);
- frag |= agnx_set_bits(PACKET_LEN, PACKET_LEN_SHIFT, skb->len);
- frag |= agnx_set_bits(FIRST_FRAG_LEN, FIRST_FRAG_LEN_SHIFT, 1);
- frag |= agnx_set_bits(OWNER, OWNER_SHIFT, 1);
- hdr_desc->frag = cpu_to_be32(frag);
- } while (0);
- hdr_desc->dma_addr = cpu_to_be32(hdr_info->mapping);
-
-
- /* Set Frag's info and desc */
- i = (i + 1) % ring->size;
- frag_desc = ring->desc + i;
- frag_info = ring->info + i;
- memcpy(frag_info, hdr_info, sizeof(struct agnx_info));
- frag_info->type = PACKET;
- frag_info->dma_len = skb->len - hdr_info->dma_len;
- frag_info->mapping = pci_map_single(priv->pdev, skb->data + hdr_info->dma_len,
- frag_info->dma_len, PCI_DMA_TODEVICE);
- do {
- u32 frag = 0;
- frag |= agnx_set_bits(FIRST_FRAG, FIRST_FRAG_SHIFT, 0);
- frag |= agnx_set_bits(LAST_FRAG, LAST_FRAG_SHIFT, 1);
- frag |= agnx_set_bits(PACKET_LEN, PACKET_LEN_SHIFT, skb->len);
- frag |= agnx_set_bits(SUB_FRAG_LEN, SUB_FRAG_LEN_SHIFT, frag_info->dma_len);
- frag_desc->frag = cpu_to_be32(frag);
- } while (0);
- frag_desc->dma_addr = cpu_to_be32(frag_info->mapping);
-
- txm_power_set(priv, txi);
-
-/* do { */
-/* int j; */
-/* size_t len; */
-/* len = skb->len - hdr_info->dma_len + hdr_info->hdr_len; */
-/* if (len == 614) { */
-/* agnx_print_desc(hdr_desc); */
-/* agnx_print_desc(frag_desc); */
-/* agnx_print_tx_hdr((struct agnx_hdr *)skb->data); */
-/* agnx_print_sta_power(priv, LOCAL_STAID); */
-/* agnx_print_sta(priv, LOCAL_STAID); */
-/* for (j = 0; j < 8; j++) */
-/* agnx_print_sta_tx_wq(priv, LOCAL_STAID, j); */
-/* agnx_print_sta_power(priv, BSSID_STAID); */
-/* agnx_print_sta(priv, BSSID_STAID); */
-/* for (j = 0; j < 8; j++) */
-/* agnx_print_sta_tx_wq(priv, BSSID_STAID, j); */
-/* } */
-/* } while (0); */
-
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* FIXME ugly code */
- /* Trigger TXM */
- do {
- u32 reg;
- reg = (ioread32(priv->ctl + AGNX_CIR_TXMCTL));
- reg |= 0x8;
- iowrite32((reg), priv->ctl + AGNX_CIR_TXMCTL);
- } while (0);
-
- /* Trigger TXD */
- do {
- u32 reg;
- reg = (ioread32(priv->ctl + AGNX_CIR_TXDCTL));
- reg |= 0x8;
- iowrite32((reg), priv->ctl + AGNX_CIR_TXDCTL);
- } while (0);
-
- return 0;
-}
-
-int _agnx_tx(struct agnx_priv *priv, struct sk_buff *skb)
-{
- u16 fctl;
-
- if (tx_packet_check(skb))
- return 0;
-
-/* print_hex_dump_bytes("agnx: TX_PACKET: ", DUMP_PREFIX_NONE, */
-/* skb->data, skb->len); */
-
- fctl = le16_to_cpu(*((__le16 *)skb->data));
-
- if ((fctl & IEEE80211_FCTL_FTYPE) == IEEE80211_FTYPE_DATA)
- return __agnx_tx(priv, skb, &priv->txd);
- else
- return __agnx_tx(priv, skb, &priv->txm);
-}
diff --git a/drivers/staging/agnx/xmit.h b/drivers/staging/agnx/xmit.h
deleted file mode 100644
index 93ac4157e697..000000000000
--- a/drivers/staging/agnx/xmit.h
+++ /dev/null
@@ -1,250 +0,0 @@
-#ifndef AGNX_XMIT_H_
-#define AGNX_XMIT_H_
-
-#include <net/mac80211.h>
-
-struct agnx_priv;
-
-static inline u32 agnx_set_bits(u32 mask, u8 shift, u32 value)
-{
- return (value << shift) & mask;
-}
-
-static inline u32 agnx_get_bits(u32 mask, u8 shift, u32 value)
-{
- return (value & mask) >> shift;
-}
-
-
-struct agnx_rx {
- __be16 rx_packet_duration; /* RX Packet Duration */
- __be16 replay_cnt; /* Replay Count */
-} __attribute__((__packed__));
-
-
-struct agnx_tx {
- u8 long_retry_limit; /* Long Retry Limit */
- u8 short_retry_limit; /* Short Retry Limit */
- u8 long_retry_cnt; /* Long Retry Count */
- u8 short_retry_cnt; /* Short Retry Count */
-} __attribute__((__packed__));
-
-
-/* Copy from bcm43xx */
-#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes]
-#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes)
-#define PAD_BYTES(nr_bytes) P4D_BYTES(__LINE__, nr_bytes)
-
-#define P4D_BIT3S(magic, nr_bits) __be32 __padding##magic:nr_bits
-#define P4D_BITS(line, nr_bits) P4D_BIT3S(line, nr_bits)
-#define PAD_BITS(nr_bits) P4D_BITS(__LINE__, nr_bits)
-
-
-struct agnx_hdr {
- __be32 reg0;
-#define RTS 0x80000000 /* RTS */
-#define RTS_SHIFT 31
-#define MULTICAST 0x40000000 /* multicast */
-#define MULTICAST_SHIFT 30
-#define ACK 0x30000000 /* ACK */
-#define ACK_SHIFT 28
-#define TM 0x08000000 /* TM */
-#define TM_SHIFT 27
-#define RELAY 0x04000000 /* Relay */
-#define RELAY_SHIFT 26
-/* PAD_BITS(4); */
-#define REVISED_FCS 0x00380000 /* revised FCS */
-#define REVISED_FCS_SHIFT 19
-#define NEXT_BUFFER_ADDR 0x0007FFFF /* Next Buffer Address */
-#define NEXT_BUFFER_ADDR_SHIFT 0
-
- __be32 reg1;
-#define MAC_HDR_LEN 0xFC000000 /* MAC Header Length */
-#define MAC_HDR_LEN_SHIFT 26
-#define DURATION_OVERIDE 0x02000000 /* Duration Override */
-#define DURATION_OVERIDE_SHIFT 25
-#define PHY_HDR_OVERIDE 0x01000000 /* PHY Header Override */
-#define PHY_HDR_OVERIDE_SHIFT 24
-#define CRC_FAIL 0x00800000 /* CRC fail */
-#define CRC_FAIL_SHIFT 23
-/* PAD_BITS(1); */
-#define SEQUENCE_NUMBER 0x00200000 /* Sequence Number */
-#define SEQUENCE_NUMBER_SHIFT 21
-/* PAD_BITS(2); */
-#define BUFF_HEAD_ADDR 0x0007FFFF /* Buffer Head Address */
-#define BUFF_HEAD_ADDR_SHIFT 0
-
- __be32 reg2;
-#define PDU_COUNT 0xFC000000 /* PDU Count */
-#define PDU_COUNT_SHIFT 26
-/* PAD_BITS(3); */
-#define WEP_KEY 0x00600000 /* WEP Key # */
-#define WEP_KEY_SHIFT 21
-#define USES_WEP_KEY 0x00100000 /* Uses WEP Key */
-#define USES_WEP_KEY_SHIFT 20
-#define KEEP_ALIVE 0x00080000 /* Keep alive */
-#define KEEP_ALIVE_SHIFT 19
-#define BUFF_TAIL_ADDR 0x0007FFFF /* Buffer Tail Address */
-#define BUFF_TAIL_ADDR_SHIFT 0
-
- __be32 reg3;
-#define CTS_11G 0x80000000 /* CTS in 11g */
-#define CTS_11G_SHIFT 31
-#define RTS_11G 0x40000000 /* RTS in 11g */
-#define RTS_11G_SHIFT 30
-/* PAD_BITS(2); */
-#define FRAG_SIZE 0x0FFF0000 /* fragment size */
-#define FRAG_SIZE_SHIFT 16
-#define PAYLOAD_LEN 0x0000FFF0 /* payload length */
-#define PAYLOAD_LEN_SHIFT 4
-#define FRAG_NUM 0x0000000F /* number of frags */
-#define FRAG_NUM_SHIFT 0
-
- __be32 reg4;
-/* PAD_BITS(4); */
-#define RELAY_STAID 0x0FFF0000 /* relayStald */
-#define RELAY_STAID_SHIFT 16
-#define STATION_ID 0x0000FFF0 /* Station ID */
-#define STATION_ID_SHIFT 4
-#define WORKQUEUE_ID 0x0000000F /* Workqueue ID */
-#define WORKQUEUE_ID_SHIFT 0
-
- /* FIXME this register maybe is LE? */
- __be32 reg5;
-/* PAD_BITS(4); */
-#define ROUTE_HOST 0x0F000000
-#define ROUTE_HOST_SHIFT 24
-#define ROUTE_CARD_CPU 0x00F00000
-#define ROUTE_CARD_CPU_SHIFT 20
-#define ROUTE_ENCRYPTION 0x000F0000
-#define ROUTE_ENCRYPTION_SHIFT 16
-#define ROUTE_TX 0x0000F000
-#define ROUTE_TX_SHIFT 12
-#define ROUTE_RX1 0x00000F00
-#define ROUTE_RX1_SHIFT 8
-#define ROUTE_RX2 0x000000F0
-#define ROUTE_RX2_SHIFT 4
-#define ROUTE_COMPRESSION 0x0000000F
-#define ROUTE_COMPRESSION_SHIFT 0
-
- __be32 _11g0; /* 11g */
- __be32 _11g1; /* 11g */
- __be32 _11b0; /* 11b */
- __be32 _11b1; /* 11b */
- u8 mac_hdr[32]; /* MAC header */
-
- __be16 rts_duration; /* RTS duration */
- __be16 last_duration; /* Last duration */
- __be16 sec_last_duration; /* Second to Last duration */
- __be16 other_duration; /* Other duration */
- __be16 tx_last_duration; /* TX Last duration */
- __be16 tx_other_duration; /* TX Other Duration */
- __be16 last_11g_len; /* Length of last 11g */
- __be16 other_11g_len; /* Lenght of other 11g */
-
- __be16 last_11b_len; /* Length of last 11b */
- __be16 other_11b_len; /* Lenght of other 11b */
-
-
- __be16 reg6;
-#define MBF 0xF000 /* mbf */
-#define MBF_SHIFT 12
-#define RSVD4 0x0FFF /* rsvd4 */
-#define RSVD4_SHIFT 0
-
- __be16 rx_frag_stat; /* RX fragmentation status */
-
- __be32 time_stamp; /* TimeStamp */
- __be32 phy_stats_hi; /* PHY stats hi */
- __be32 phy_stats_lo; /* PHY stats lo */
- __be32 mic_key0; /* MIC key 0 */
- __be32 mic_key1; /* MIC key 1 */
-
- union { /* RX/TX Union */
- struct agnx_rx rx;
- struct agnx_tx tx;
- };
-
- u8 rx_channel; /* Recieve Channel */
- PAD_BYTES(3);
-
- u8 reserved[4];
-} __attribute__((__packed__));
-
-
-struct agnx_desc {
-#define PACKET_LEN 0xFFF00000
-#define PACKET_LEN_SHIFT 20
-/* ------------------------------------------------ */
-#define FIRST_PACKET_MASK 0x00080000
-#define FIRST_PACKET_MASK_SHIFT 19
-#define FIRST_RESERV2 0x00040000
-#define FIRST_RESERV2_SHIFT 18
-#define FIRST_TKIP_ERROR 0x00020000
-#define FIRST_TKIP_ERROR_SHIFT 17
-#define FIRST_TKIP_PACKET 0x00010000
-#define FIRST_TKIP_PACKET_SHIFT 16
-#define FIRST_RESERV1 0x0000F000
-#define FIRST_RESERV1_SHIFT 12
-#define FIRST_FRAG_LEN 0x00000FF8
-#define FIRST_FRAG_LEN_SHIFT 3
-/* ------------------------------------------------ */
-#define SUB_RESERV2 0x000c0000
-#define SUB_RESERV2_SHIFT 18
-#define SUB_TKIP_ERROR 0x00020000
-#define SUB_TKIP_ERROR_SHIFT 17
-#define SUB_TKIP_PACKET 0x00010000
-#define SUB_TKIP_PACKET_SHIFT 16
-#define SUB_RESERV1 0x00008000
-#define SUB_RESERV1_SHIFT 15
-#define SUB_FRAG_LEN 0x00007FF8
-#define SUB_FRAG_LEN_SHIFT 3
-/* ------------------------------------------------ */
-#define FIRST_FRAG 0x00000004
-#define FIRST_FRAG_SHIFT 2
-#define LAST_FRAG 0x00000002
-#define LAST_FRAG_SHIFT 1
-#define OWNER 0x00000001
-#define OWNER_SHIFT 0
- __be32 frag;
- __be32 dma_addr;
-} __attribute__((__packed__));
-
-enum {HEADER, PACKET};
-
-struct agnx_info {
- struct sk_buff *skb;
- dma_addr_t mapping;
- u32 dma_len; /* dma buffer len */
- /* Below fields only usful for tx */
- u32 hdr_len; /* ieee80211 header length */
- unsigned int type;
- struct ieee80211_tx_info *txi;
- struct ieee80211_hdr hdr;
-};
-
-
-struct agnx_ring {
- struct agnx_desc *desc;
- dma_addr_t dma;
- struct agnx_info *info;
- /* Will lead to overflow when sent packet number enough? */
- unsigned int idx;
- unsigned int idx_sent; /* only usful for txd and txm */
- unsigned int size;
-};
-
-#define AGNX_RX_RING_SIZE 128
-#define AGNX_TXD_RING_SIZE 256
-#define AGNX_TXM_RING_SIZE 128
-
-void disable_rx_interrupt(struct agnx_priv *priv);
-void enable_rx_interrupt(struct agnx_priv *priv);
-int fill_rings(struct agnx_priv *priv);
-void unfill_rings(struct agnx_priv *priv);
-void handle_rx_irq(struct agnx_priv *priv);
-void handle_txd_irq(struct agnx_priv *priv);
-void handle_txm_irq(struct agnx_priv *priv);
-void handle_other_irq(struct agnx_priv *priv);
-int _agnx_tx(struct agnx_priv *priv, struct sk_buff *skb);
-#endif /* AGNX_XMIT_H_ */
diff --git a/drivers/staging/b3dfg/b3dfg.c b/drivers/staging/b3dfg/b3dfg.c
index 94c5d27d24d7..cda26bb493b3 100644
--- a/drivers/staging/b3dfg/b3dfg.c
+++ b/drivers/staging/b3dfg/b3dfg.c
@@ -36,6 +36,7 @@
#include <linux/wait.h>
#include <linux/mm.h>
#include <linux/uaccess.h>
+#include <linux/sched.h>
static unsigned int b3dfg_nbuf = 2;
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index af723cb9d08f..d63c889ce557 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -1,7 +1,7 @@
config COMEDI
tristate "Data acquisition support (comedi)"
default N
- depends on m
+ depends on m && (PCI || PCMCIA || PCCARD || USB)
---help---
Enable support a wide range of data acquisition devices
for Linux.
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index f54bb9b3ee37..aaad76e0a76a 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -2337,7 +2337,7 @@ static int resize_async_buffer(struct comedi_device *dev,
}
DPRINTK("comedi%i subd %d buffer resized to %i bytes\n",
- dev->minor, s - dev->subdevices, async->prealloc_bufsz);
+ dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz);
return 0;
}
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 12d12b43a6f1..80c0df8656f3 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -744,7 +744,7 @@ static int das16cs_pcmcia_attach(struct pcmcia_device *link)
/* Initialize the pcmcia_device structure */
/* Interrupt setup */
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = NULL;
diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c
index 4d10bc31d461..09e6e3bdfb3e 100644
--- a/drivers/staging/comedi/drivers/cb_pcidio.c
+++ b/drivers/staging/comedi/drivers/cb_pcidio.c
@@ -53,7 +53,8 @@ Passing a zero for an option is the same as leaving it unspecified.
* Some drivers use arrays such as this, other do not.
*/
struct pcidio_board {
- const char *name; /* anme of the board */
+ const char *name; /* name of the board */
+ int dev_id;
int n_8255; /* number of 8255 chips on board */
/* indices of base address regions */
@@ -64,18 +65,21 @@ struct pcidio_board {
static const struct pcidio_board pcidio_boards[] = {
{
.name = "pci-dio24",
+ .dev_id = 0x0028,
.n_8255 = 1,
.pcicontroler_badrindex = 1,
.dioregs_badrindex = 2,
},
{
.name = "pci-dio24h",
+ .dev_id = 0x0014,
.n_8255 = 1,
.pcicontroler_badrindex = 1,
.dioregs_badrindex = 2,
},
{
.name = "pci-dio48h",
+ .dev_id = 0x000b,
.n_8255 = 2,
.pcicontroler_badrindex = 0,
.dioregs_badrindex = 1,
@@ -206,7 +210,7 @@ static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
continue;
/* loop through cards supported by this driver */
for (index = 0; index < ARRAY_SIZE(pcidio_boards); index++) {
- if (pcidio_pci_table[index].device != pcidev->device)
+ if (pcidio_boards[index].dev_id != pcidev->device)
continue;
/* was a particular bus/slot requested? */
diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c
index 14bf29bf5781..0d2c2eb23b23 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.c
+++ b/drivers/staging/comedi/drivers/jr3_pci.c
@@ -515,6 +515,7 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice *s)
{
struct poll_delay_t result = poll_delay_min_max(1000, 2000);
struct jr3_pci_subdev_private *p = s->private;
+ int i;
if (p) {
volatile struct jr3_channel *channel = p->channel;
@@ -570,18 +571,11 @@ static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice *s)
p->serial_no);
/* Transformation all zeros */
- transf.link[0].link_type =
- (enum link_types)0;
- transf.link[0].link_amount = 0;
- transf.link[1].link_type =
- (enum link_types)0;
- transf.link[1].link_amount = 0;
- transf.link[2].link_type =
- (enum link_types)0;
- transf.link[2].link_amount = 0;
- transf.link[3].link_type =
- (enum link_types)0;
- transf.link[3].link_amount = 0;
+ for (i = 0; i < ARRAY_SIZE(transf.link); i++) {
+ transf.link[i].link_type =
+ (enum link_types)0;
+ transf.link[i].link_amount = 0;
+ }
set_transforms(channel, transf, 0);
use_transform(channel, 0);
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index 2cda7ad1d32f..80e192d2e77e 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -51,6 +51,7 @@ from http://www.comedi.org
*/
#include <linux/interrupt.h>
+#include <linux/sched.h>
#include "../comedidev.h"
#include "comedi_pci.h"
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index 6b118c15b49e..bbf75eb6d7f2 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -418,15 +418,15 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
return -EINVAL;
base_bitfield_channel = CR_CHAN(insn->chanspec);
for (j = 0; j < max_ports_per_bitfield; ++j) {
+ const unsigned port_offset = ni_65xx_port_by_channel(base_bitfield_channel) + j;
const unsigned port =
- sprivate(s)->base_port +
- ni_65xx_port_by_channel(base_bitfield_channel) + j;
+ sprivate(s)->base_port + port_offset;
unsigned base_port_channel;
unsigned port_mask, port_data, port_read_bits;
int bitshift;
if (port >= ni_65xx_total_num_ports(board(dev)))
break;
- base_port_channel = port * ni_65xx_channels_per_port;
+ base_port_channel = port_offset * ni_65xx_channels_per_port;
port_mask = data[0];
port_data = data[1];
bitshift = base_port_channel - base_bitfield_channel;
@@ -457,6 +457,12 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev,
port_read_bits =
readb(private(dev)->mite->daq_io_addr + Port_Data(port));
/* printk("read 0x%x from port %i\n", port_read_bits, port); */
+ if (s->type == COMEDI_SUBD_DO && board(dev)->invert_outputs) {
+ /* Outputs inverted, so invert value read back from
+ * DO subdevice. (Does not apply to boards with DIO
+ * subdevice.) */
+ port_read_bits ^= 0xFF;
+ }
if (bitshift > 0) {
port_read_bits <<= bitshift;
} else {
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index 6a7797604c97..ec31a3970664 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -520,7 +520,7 @@ static int dio700_cs_attach(struct pcmcia_device *link)
link->priv = local;
/* Interrupt setup */
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = NULL;
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index b06e81c526e8..0700a8bddd1e 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -271,7 +271,7 @@ static int dio24_cs_attach(struct pcmcia_device *link)
link->priv = local;
/* Interrupt setup */
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = NULL;
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index 57aecfa883c7..a3053b8da1c6 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -246,7 +246,7 @@ static int labpc_cs_attach(struct pcmcia_device *link)
link->priv = local;
/* Interrupt setup */
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_FORCED_PULSE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FORCED_PULSE;
link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_PULSE_ID;
link->irq.Handler = NULL;
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index e3ffb067ead1..753ee0512342 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -62,6 +62,7 @@
/* #define DEBUG_STATUS_B */
#include <linux/interrupt.h>
+#include <linux/sched.h>
#include "8255.h"
#include "mite.h"
#include "comedi_fc.h"
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index b7322963cf78..9aef87fc81dc 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -273,7 +273,7 @@ static int cs_attach(struct pcmcia_device *link)
{
link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
link->io.NumPorts1 = 16;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index 52b2eca9e73d..d544698f2414 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -70,6 +70,7 @@ comedi_nonfree_firmware tarball available from http://www.comedi.org
/* #define DEBUG_FLAGS */
#include <linux/interrupt.h>
+#include <linux/sched.h>
#include "../comedidev.h"
#include "mite.h"
diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c
index 19d87553d906..24c8b8ed5b4c 100644
--- a/drivers/staging/comedi/drivers/ni_pcimio.c
+++ b/drivers/staging/comedi/drivers/ni_pcimio.c
@@ -29,7 +29,7 @@ Devices: [National Instruments] PCI-MIO-16XE-50 (ni_pcimio),
PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, PCI-MIO-16E-4, PCI-6014, PCI-6040E,
PXI-6040E, PCI-6030E, PCI-6031E, PCI-6032E, PCI-6033E, PCI-6071E, PCI-6023E,
PCI-6024E, PCI-6025E, PXI-6025E, PCI-6034E, PCI-6035E, PCI-6052E,
- PCI-6110, PCI-6111, PCI-6220, PCI-6221, PCI-6224, PXI-6224, PCI-6225,
+ PCI-6110, PCI-6111, PCI-6220, PCI-6221, PCI-6224, PXI-6224, PCI-6225, PXI-6225,
PCI-6229, PCI-6250, PCI-6251, PCIe-6251, PCI-6254, PCI-6259, PCIe-6259,
PCI-6280, PCI-6281, PXI-6281, PCI-6284, PCI-6289,
PCI-6711, PXI-6711, PCI-6713, PXI-6713,
@@ -179,6 +179,7 @@ static DEFINE_PCI_DEVICE_TABLE(ni_pci_table) = {
PCI_VENDOR_ID_NATINST, 0x70f2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_NATINST, 0x710d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_NATINST, 0x716c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
+ PCI_VENDOR_ID_NATINST, 0x716d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_NATINST, 0x717f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_NATINST, 0x71bc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
PCI_VENDOR_ID_NATINST, 0x717d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {
@@ -953,6 +954,25 @@ static const struct ni_board_struct ni_boards[] = {
.has_8255 = 0,
},
{
+ .device_id = 0x716d,
+ .name = "pxi-6225",
+ .n_adchan = 80,
+ .adbits = 16,
+ .ai_fifo_depth = 4095,
+ .gainlkup = ai_gain_622x,
+ .ai_speed = 4000,
+ .n_aochan = 2,
+ .aobits = 16,
+ .ao_fifo_depth = 8191,
+ .ao_range_table = &range_ni_M_622x_ao,
+ .reg_type = ni_reg_622x,
+ .ao_unipolar = 0,
+ .ao_speed = 1200,
+ .num_p0_dio_channels = 32,
+ .caldac = {caldac_none},
+ .has_8255 = 0,
+ },
+ {
.device_id = 0x70aa,
.name = "pci-6229",
.n_adchan = 32,
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index f63bdc35cffd..344b82353e08 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -1079,7 +1079,7 @@ static int daqp_cs_attach(struct pcmcia_device *link)
link->priv = local;
/* Interrupt setup */
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = daqp_interrupt;
link->irq.Instance = local;
diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c
index b89e1ec267c5..07c21e686f27 100644
--- a/drivers/staging/comedi/drivers/s526.c
+++ b/drivers/staging/comedi/drivers/s526.c
@@ -43,6 +43,7 @@ comedi_config /dev/comedi0 s526 0x2C0,0x3
#include "../comedidev.h"
#include <linux/ioport.h>
+#include <asm/byteorder.h>
#define S526_SIZE 64
@@ -113,6 +114,7 @@ static const int s526_ports[] = {
};
struct counter_mode_register_t {
+#if defined (__LITTLE_ENDIAN_BITFIELD)
unsigned short coutSource:1;
unsigned short coutPolarity:1;
unsigned short autoLoadResetRcap:3;
@@ -124,12 +126,27 @@ struct counter_mode_register_t {
unsigned short outputRegLatchCtrl:1;
unsigned short preloadRegSel:1;
unsigned short reserved:1;
+ #elif defined(__BIG_ENDIAN_BITFIELD)
+ unsigned short reserved:1;
+ unsigned short preloadRegSel:1;
+ unsigned short outputRegLatchCtrl:1;
+ unsigned short countDirCtrl:1;
+ unsigned short countDir:1;
+ unsigned short clockSource:2;
+ unsigned short ctEnableCtrl:2;
+ unsigned short hwCtEnableSource:2;
+ unsigned short autoLoadResetRcap:3;
+ unsigned short coutPolarity:1;
+ unsigned short coutSource:1;
+#else
+#error Unknown bit field order
+#endif
};
-union {
+union cmReg {
struct counter_mode_register_t reg;
unsigned short value;
-} cmReg;
+};
#define MAX_GPCT_CONFIG_DATA 6
@@ -285,6 +302,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int i, n;
/* short value; */
/* int subdev_channel = 0; */
+ union cmReg cmReg;
printk("comedi%d: s526: ", dev->minor);
@@ -375,7 +393,7 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (thisboard->have_dio) {
s->type = COMEDI_SUBD_DIO;
s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 2;
+ s->n_chan = 8;
s->maxdata = 1;
s->range_table = &range_digital;
s->insn_bits = s526_dio_insn_bits;
@@ -435,11 +453,11 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it)
udelay(1000);
printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n)));
- /* Load the pre-laod register high word */
+ /* Load the pre-load register high word */
/* value = (short) (0x55); */
/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */
- /* Load the pre-laod register low word */
+ /* Load the pre-load register low word */
/* value = (short)(0xaa55); */
/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */
@@ -516,6 +534,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */
int i;
short value;
+ union cmReg cmReg;
/* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", subdev_channel); */
@@ -568,19 +587,8 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
#if 1
/* Set Counter Mode Register */
- cmReg.reg.coutSource = 0; /* out RCAP */
- cmReg.reg.coutPolarity = 0; /* Polarity inverted */
- cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */
- cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */
- cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */
- cmReg.reg.clockSource = 3; /* x4 */
- cmReg.reg.countDir = 0; /* up */
- cmReg.reg.countDirCtrl = 0; /* quadrature */
- cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */
- cmReg.reg.preloadRegSel = 0; /* PR0 */
- cmReg.reg.reserved = 0;
+ cmReg.value = insn->data[1] & 0xFFFF;
- /* Set Counter Mode Register */
/* printk("s526: Counter Mode register=%x\n", cmReg.value); */
outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
@@ -615,11 +623,11 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
cmReg.value = (short)(insn->data[1] & 0xFFFF);
outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
- /* Load the pre-laod register high word */
+ /* Load the pre-load register high word */
value = (short)((insn->data[2] >> 16) & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
- /* Load the pre-laod register low word */
+ /* Load the pre-load register low word */
value = (short)(insn->data[2] & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
@@ -653,11 +661,11 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
cmReg.reg.preloadRegSel = 0; /* PR0 */
outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
- /* Load the pre-laod register 0 high word */
+ /* Load the pre-load register 0 high word */
value = (short)((insn->data[2] >> 16) & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
- /* Load the pre-laod register 0 low word */
+ /* Load the pre-load register 0 low word */
value = (short)(insn->data[2] & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
@@ -666,17 +674,17 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
cmReg.reg.preloadRegSel = 1; /* PR1 */
outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
- /* Load the pre-laod register 1 high word */
+ /* Load the pre-load register 1 high word */
value = (short)((insn->data[3] >> 16) & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
- /* Load the pre-laod register 1 low word */
+ /* Load the pre-load register 1 low word */
value = (short)(insn->data[3] & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
/* Write the Counter Control Register */
- if (insn->data[3] != 0) {
- value = (short)(insn->data[3] & 0xFFFF);
+ if (insn->data[4] != 0) {
+ value = (short)(insn->data[4] & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
}
break;
@@ -698,11 +706,11 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
cmReg.reg.preloadRegSel = 0; /* PR0 */
outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
- /* Load the pre-laod register 0 high word */
+ /* Load the pre-load register 0 high word */
value = (short)((insn->data[2] >> 16) & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
- /* Load the pre-laod register 0 low word */
+ /* Load the pre-load register 0 low word */
value = (short)(insn->data[2] & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
@@ -711,17 +719,17 @@ static int s526_gpct_insn_config(struct comedi_device *dev,
cmReg.reg.preloadRegSel = 1; /* PR1 */
outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
- /* Load the pre-laod register 1 high word */
+ /* Load the pre-load register 1 high word */
value = (short)((insn->data[3] >> 16) & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
- /* Load the pre-laod register 1 low word */
+ /* Load the pre-load register 1 low word */
value = (short)(insn->data[3] & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
/* Write the Counter Control Register */
- if (insn->data[3] != 0) {
- value = (short)(insn->data[3] & 0xFFFF);
+ if (insn->data[4] != 0) {
+ value = (short)(insn->data[4] & 0xFFFF);
outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
}
break;
@@ -741,6 +749,7 @@ static int s526_gpct_winsn(struct comedi_device *dev,
{
int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */
short value;
+ union cmReg cmReg;
printk("s526: GPCT_INSN_WRITE on channel %d\n", subdev_channel);
cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel));
@@ -775,9 +784,8 @@ static int s526_gpct_winsn(struct comedi_device *dev,
(devpriv->s526_gpct_config[subdev_channel]).data[1] =
insn->data[1];
} else {
- printk("%d \t %d\n", insn->data[1], insn->data[2]);
- printk
- ("s526: INSN_WRITE: PTG: Problem with Pulse params\n");
+ printk("s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n",
+ insn->data[0], insn->data[1]);
return -EINVAL;
}
@@ -949,7 +957,7 @@ static int s526_dio_insn_bits(struct comedi_device *dev,
data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */
/* or we could just return the software copy of the output values if
* it was a purely digital output subdevice */
- /* data[1]=s->state; */
+ /* data[1]=s->state & 0xFF; */
return 2;
}
@@ -959,28 +967,33 @@ static int s526_dio_insn_config(struct comedi_device *dev,
struct comedi_insn *insn, unsigned int *data)
{
int chan = CR_CHAN(insn->chanspec);
- short value;
+ int group, mask;
printk("S526 DIO insn_config\n");
- if (insn->n != 1)
- return -EINVAL;
-
- value = inw(ADDR_REG(REG_DIO));
-
/* The input or output configuration of each digital line is
* configured by a special insn_config instruction. chanspec
* contains the channel to be changed, and data[0] contains the
* value COMEDI_INPUT or COMEDI_OUTPUT. */
- if (data[0] == COMEDI_OUTPUT) {
- value |= 1 << (chan + 10); /* bit 10/11 set the group 1/2's mode */
- s->io_bits |= (0xF << chan);
- } else {
- value &= ~(1 << (chan + 10)); /* 1 is output, 0 is input. */
- s->io_bits &= ~(0xF << chan);
+ group = chan >> 2;
+ mask = 0xF << (group << 2);
+ switch (data[0]) {
+ case INSN_CONFIG_DIO_OUTPUT:
+ s->state |= 1 << (group + 10); // bit 10/11 set the group 1/2's mode
+ s->io_bits |= mask;
+ break;
+ case INSN_CONFIG_DIO_INPUT:
+ s->state &= ~(1 << (group + 10));// 1 is output, 0 is input.
+ s->io_bits &= ~mask;
+ break;
+ case INSN_CONFIG_DIO_QUERY:
+ data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
+ return insn->n;
+ default:
+ return -EINVAL;
}
- outw(value, ADDR_REG(REG_DIO));
+ outw(s->state, ADDR_REG(REG_DIO));
return 1;
}
diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c
index a21967983942..82aa86e718b2 100644
--- a/drivers/staging/comedi/drivers/serial2002.c
+++ b/drivers/staging/comedi/drivers/serial2002.c
@@ -35,6 +35,7 @@ Status: in development
#include <linux/delay.h>
#include <linux/ioport.h>
+#include <linux/sched.h>
#include <asm/termios.h>
#include <asm/ioctls.h>
diff --git a/drivers/staging/cowloop/Kconfig b/drivers/staging/cowloop/Kconfig
deleted file mode 100644
index 58d2a23bd2c1..000000000000
--- a/drivers/staging/cowloop/Kconfig
+++ /dev/null
@@ -1,16 +0,0 @@
-config COWLOOP
- tristate "copy-on-write pseudo Block Driver"
- depends on BLOCK
- default n
- ---help---
- Cowloop is a "copy-on-write" pseudo block driver. It can be
- stacked on top of a "real" block driver, and catches all write
- operations on their way from the file systems layer above to
- the real driver below, effectively shielding the lower driver
- from those write accesses. The requests are then diverted to
- an ordinary file, located somewhere else (configurable). Later
- read requests are checked to see whether they can be serviced
- by the "real" block driver below, or must be pulled in from
- the diverted location. More information and userspace tools to
- use the driver are on the project's website
- http://www.ATComputing.nl/cowloop/
diff --git a/drivers/staging/cowloop/Makefile b/drivers/staging/cowloop/Makefile
deleted file mode 100644
index 2b6b81a63d21..000000000000
--- a/drivers/staging/cowloop/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-obj-$(CONFIG_COWLOOP) += cowloop.o
diff --git a/drivers/staging/cowloop/TODO b/drivers/staging/cowloop/TODO
deleted file mode 100644
index 9399d1c16e15..000000000000
--- a/drivers/staging/cowloop/TODO
+++ /dev/null
@@ -1,11 +0,0 @@
-TODO:
- - checkpatch.pl cleanups
- - run sparse to ensure clean
- - fix up 32/64bit ioctl issues
- - move proc file usage to debugfs
- - audit ioctls
- - add documentation
- - get linux-fsdevel to review it
-
-Please send patches to "H.J. Thomassen" <hjt@ATComputing.nl> and
-Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/staging/cowloop/cowloop.c b/drivers/staging/cowloop/cowloop.c
deleted file mode 100644
index a71c743a1196..000000000000
--- a/drivers/staging/cowloop/cowloop.c
+++ /dev/null
@@ -1,2842 +0,0 @@
-/*
-** COWLOOP block device driver (2.6 kernel compliant)
-** =======================================================================
-** Read-write loop-driver with copy-on-write functionality.
-**
-** Synopsis:
-**
-** modprobe cowloop [maxcows=..] [rdofile=..... cowfile=.... [option=r]]
-**
-** Definition of number of configured cowdevices:
-** maxcows= number of configured cowdevices (default: 16)
-** (do not confuse this with MAXCOWS: absolute maximum as compiled)
-**
-** One pair of filenames can be supplied during insmod/modprobe to open
-** the first cowdevice:
-** rdofile= read-only file (or filesystem)
-** cowfile= storage-space for modified blocks of read-only file(system)
-** option=r repair cowfile automatically if it appears to be dirty
-**
-** Other cowdevices can be activated via the command "cowdev"
-** whenever the cowloop-driver is loaded.
-**
-** The read-only file may be of type 'regular' or 'block-device'.
-**
-** The cowfile must be of type 'regular'.
-** If an existing regular file is used as cowfile, its contents will be
-** used again for the current read-only file. When the cowfile has not been
-** closed properly during a previous session (i.e. rmmod cowloop), the
-** cowloop-driver refuses to open it unless the parameter "option=r" is
-** specified.
-**
-** Layout of cowfile:
-**
-** +-----------------------------+
-** | cow head block | MAPUNIT bytes
-** |-----------------------------|
-** | | MAPUNIT bytes
-** |--- ---|
-** | | MAPUNIT bytes
-** |--- ---|
-** | used-block bitmap | MAPUNIT bytes
-** |-----------------------------|
-** | gap to align start-offset |
-** | to 4K multiple |
-** |-----------------------------| <---- start-offset cow blocks
-** | |
-** | written cow blocks | MAPUNIT bytes
-** | ..... |
-**
-** cowhead block:
-** - contains general info about the rdofile which is related
-** to this cowfile
-**
-** used-block bitmap:
-** - contains one bit per block with a size of MAPUNIT bytes
-** - bit-value '1' = block has been written on cow
-** '0' = block unused on cow
-** - total bitmap rounded to multiples of MAPUNIT
-**
-** ============================================================================
-** Author: Gerlof Langeveld - AT Computing (March 2003)
-** Current maintainer: Hendrik-Jan Thomassen - AT Computing (Summer 2006)
-** Email: hjt@ATComputing.nl
-** ----------------------------------------------------------------------------
-** Copyright (C) 2003-2009 AT Consultancy
-**
-** This program is free software; you can redistribute it and/or modify it
-** under the terms of the GNU General Public License as published by the
-** Free Software Foundation; either version 2, or (at your option) any
-** later version.
-**
-** This program is distributed in the hope that it will be useful, but
-** WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-** See the GNU General Public License for more details.
-**
-** You 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
-** ----------------------------------------------------------------------------
-**
-** Major modifications:
-**
-** 200405 Ported to kernel-version 2.6 Hendrik-Jan Thomassen
-** 200405 Added cowhead to cowfile to garantee
-** consistency with read-only file Gerlof Langeveld
-** 200405 Postponed flushing of bitmaps to improve
-** performance. Gerlof Langeveld
-** 200405 Inline recovery for dirty cowfiles. Gerlof Langeveld
-** 200502 Redesign to support more cowdevices. Gerlof Langeveld
-** 200502 Support devices/file > 2 Gbytes. Gerlof Langeveld
-** 200507 Check for free space to expand cowfile. Gerlof Langeveld
-** 200902 Upgrade for kernel 2.6.28 Hendrik-Jan Thomassen
-**
-** Inspired by
-** loop.c by Theodore Ts'o and
-** cloop.c by Paul `Rusty' Russell & Klaus Knopper.
-**
-** Design-considerations:
-**
-** For the first experiments with the cowloop-driver, the request-queue
-** made use of the do_generic_file_read() which worked fine except
-** in combination with the cloop-driver; that combination
-** resulted in a non-interruptible hangup of the system during
-** heavy load. Other experiments using the `make_request' interface also
-** resulted in unpredictable system hangups (with proper use of spinlocks).
-**
-** To overcome these problems, the cowloop-driver starts a kernel-thread
-** for every active cowdevice.
-** All read- and write-request on the read-only file and copy-on-write file
-** are handled in the context of that thread.
-** A scheme has been designed to wakeup the kernel-thread as
-** soon as I/O-requests are available in the request-queue; this thread
-** handles the requests one-by-one by calling the proper read- or
-** write-function related to the open read-only file or copy-on-write file.
-** When all pending requests have been handled, the kernel-thread goes
-** back to sleep-state.
-** This approach requires some additional context-switches; however the
-** performance loss during heavy I/O is less than 3%.
-**
-** -------------------------------------------------------------------------*/
-/* The following is the cowloop package version number. It must be
- identical to the content of the include-file "version.h" that is
- used in all supporting utilities: */
-char revision[] = "$Revision: 3.1 $"; /* cowlo_init_module() has
- assumptions about this string's format */
-
-/* Note that the following numbers are *not* the cowloop package version
- numbers, but separate revision history numbers to track the
- modifications of this particular source file: */
-/* $Log: cowloop.c,v $
-**
-** Revision 1.30 2009/02/08 hjt
-** Integrated earlier fixes
-** Upgraded to kernel 2.6.28 (thanks Jerome Poulin)
-**
-** Revision 1.29 2006/12/03 22:12:00 hjt
-** changed 'cowdevlock' from spinlock to semaphore, to avoid
-** "scheduling while atomic". Contributed by Juergen Christ.
-** Added version.h again
-**
-** Revision 1.28 2006/08/16 16:00:00 hjt
-** malloc each individual cowloopdevice struct separately
-**
-** Revision 1.27 2006/03/14 14:57:03 root
-** Removed include version.h
-**
-** Revision 1.26 2005/08/08 11:22:48 root
-** Implement possibility to close a cow file or reopen a cowfile read-only.
-**
-** Revision 1.25 2005/08/03 14:00:39 root
-** Added modinfo info to driver.
-**
-** Revision 1.24 2005/07/21 06:14:53 root
-** Cosmetic changes source code.
-**
-** Revision 1.23 2005/07/20 13:07:32 root
-** Supply ioctl to write watchdog program to react on lack of cowfile space.
-**
-** Revision 1.22 2005/07/20 07:53:34 root
-** Regular verification of free space in filesystem holding the cowfile
-** (give warnings whenever space is almost exhausted).
-** Terminology change: checksum renamed to fingerprint.
-**
-** Revision 1.21 2005/07/19 09:21:52 root
-** Removing maximum limit of 16 Gb per cowdevice.
-**
-** Revision 1.20 2005/07/19 07:50:33 root
-** Minor bugfixes and cosmetic changes.
-**
-** Revision 1.19 2005/06/10 12:29:55 root
-** Removed lock/unlock operation from cowlo_open().
-**
-** Revision 1.18 2005/05/09 12:56:26 root
-** Allow a cowdevice to be open more than once
-** (needed for support of ReiserFS and XFS).
-**
-** Revision 1.17 2005/03/17 14:36:16 root
-** Fixed some license issues.
-**
-** Revision 1.16 2005/03/07 14:42:05 root
-** Only allow one parallel open per cowdevice.
-**
-** Revision 1.15 2005/02/18 11:52:04 gerlof
-** Redesign to support more than one cowdevice > 2 Gb space.
-**
-** Revision 1.14 2004/08/17 14:19:16 gerlof
-** Modified output of /proc/cowloop.
-**
-** Revision 1.13 2004/08/16 07:21:10 gerlof
-** Separate statistical counter for read on rdofile and cowfile.
-**
-** Revision 1.12 2004/08/11 06:52:11 gerlof
-** Modified messages.
-**
-** Revision 1.11 2004/08/11 06:44:11 gerlof
-** Modified log messages.
-**
-** Revision 1.10 2004/08/10 12:27:27 gerlof
-** Cosmetic changes.
-**
-** Revision 1.9 2004/08/09 11:43:37 gerlof
-** Removed double definition of major number (COWMAJOR).
-**
-** Revision 1.8 2004/08/09 08:03:39 gerlof
-** Cleanup of messages.
-**
-** Revision 1.7 2004/05/27 06:37:33 gerlof
-** Modified /proc message.
-**
-** Revision 1.6 2004/05/26 21:23:28 gerlof
-** Modified /proc output.
-**
-** Revision 1.5 2004/05/26 13:23:34 gerlof
-** Support cowsync to force flushing the bitmaps and cowhead.
-**
-** Revision 1.4 2004/05/26 11:11:10 gerlof
-** Updated the comment to the actual situation.
-**
-** Revision 1.3 2004/05/26 10:50:00 gerlof
-** Implemented recovery-option.
-**
-** Revision 1.2 2004/05/25 15:14:41 gerlof
-** Modified bitmap flushing strategy.
-**
-*/
-
-#define COWMAJOR 241
-
-// #define COWDEBUG
-
-#ifdef COWDEBUG
-#define DEBUGP printk
-#define DCOW KERN_ALERT
-#else
-#define DEBUGP(format, x...)
-#endif
-
-#include <linux/types.h>
-#include <linux/autoconf.h>
-#ifndef AUTOCONF_INCLUDED
-#include <linux/config.h>
-#endif
-#include <linux/module.h>
-#include <linux/version.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/stat.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/semaphore.h>
-#include <asm/uaccess.h>
-#include <linux/proc_fs.h>
-#include <linux/blkdev.h>
-#include <linux/buffer_head.h>
-#include <linux/hdreg.h>
-#include <linux/genhd.h>
-#include <linux/statfs.h>
-
-#include "cowloop.h"
-
-MODULE_LICENSE("GPL");
-/* MODULE_AUTHOR("Gerlof Langeveld <gerlof@ATComputing.nl>"); obsolete address */
-MODULE_AUTHOR("Hendrik-Jan Thomassen <hjt@ATComputing.nl>"); /* current maintainer */
-MODULE_DESCRIPTION("Copy-on-write loop driver");
-MODULE_PARM_DESC(maxcows, " Number of configured cowdevices (default 16)");
-MODULE_PARM_DESC(rdofile, " Read-only file for /dev/cow/0");
-MODULE_PARM_DESC(cowfile, " Cowfile for /dev/cow/0");
-MODULE_PARM_DESC(option, " Repair cowfile if inconsistent: option=r");
-
-#define DEVICE_NAME "cow"
-
-#define DFLCOWS 16 /* default cowloop devices */
-
-static int maxcows = DFLCOWS;
-module_param(maxcows, int, 0);
-static char *rdofile = "";
-module_param(rdofile, charp, 0);
-static char *cowfile = "";
-module_param(cowfile, charp, 0);
-static char *option = "";
-module_param(option, charp, 0);
-
-/*
-** per cowdevice several bitmap chunks are allowed of MAPCHUNKSZ each
-**
-** each bitmap chunk can describe MAPCHUNKSZ * 8 * MAPUNIT bytes of data
-** suppose:
-** MAPCHUNKSZ 4096 and MAPUNIT 1024 --> 4096 * 8 * 1024 = 32 Mb per chunk
-*/
-#define MAPCHUNKSZ 4096 /* #bytes per bitmap chunk (do not change) */
-
-#define SPCMINBLK 100 /* space threshold to give warning messages */
-#define SPCDFLINTVL 16 /* once every SPCDFLINTVL writes to cowfile, */
- /* available space in filesystem is checked */
-
-#define CALCMAP(x) ((x)/(MAPCHUNKSZ*8))
-#define CALCBYTE(x) (((x)%(MAPCHUNKSZ*8))>>3)
-#define CALCBIT(x) ((x)&7)
-
-#define ALLCOW 1
-#define ALLRDO 2
-#define MIXEDUP 3
-
-static char allzeroes[MAPUNIT];
-
-/*
-** administration per cowdevice (pair of cowfile/rdofile)
-*/
-
-/* bit-values for state */
-#define COWDEVOPEN 0x01 /* cowdevice opened */
-#define COWRWCOWOPEN 0x02 /* cowfile opened read-write */
-#define COWRDCOWOPEN 0x04 /* cowfile opened read-only */
-#define COWWATCHDOG 0x08 /* ioctl for watchdog cowfile space active */
-
-#define COWCOWOPEN (COWRWCOWOPEN|COWRDCOWOPEN)
-
-struct cowloop_device
-{
- /*
- ** current status
- */
- int state; /* bit-values (see above) */
- int opencnt; /* # opens for cowdevice */
-
- /*
- ** open file pointers
- */
- struct file *rdofp, *cowfp; /* open file pointers */
- char *rdoname, *cowname; /* file names */
-
- /*
- ** request queue administration
- */
- struct request_queue *rqueue;
- spinlock_t rqlock;
- struct gendisk *gd;
-
- /*
- ** administration about read-only file
- */
- unsigned int numblocks; /* # blocks input file in MAPUNIT */
- unsigned int blocksz; /* minimum unit to access this dev */
- unsigned long fingerprint; /* fingerprint of current rdofile */
- struct block_device *belowdev; /* block device below us */
- struct gendisk *belowgd; /* gendisk for blk dev below us */
- struct request_queue *belowq; /* req. queue of blk dev below us */
-
- /*
- ** bitmap administration to register which blocks are modified
- */
- long int mapsize; /* total size of bitmap (bytes) */
- long int mapremain; /* remaining bytes in last bitmap */
- int mapcount; /* number of bitmaps in use */
- char **mapcache; /* area with pointers to bitmaps */
-
- char *iobuf; /* databuffer of MAPUNIT bytes */
- struct cowhead *cowhead; /* buffer containing cowhead */
-
- /*
- ** administration for interface with the kernel-thread
- */
- int pid; /* pid==0: no thread available */
- struct request *req; /* request to be handled now */
- wait_queue_head_t waitq; /* wait-Q: thread waits for work */
- char closedown; /* boolean: thread exit required */
- char qfilled; /* boolean: I/O request pending */
- char iobusy; /* boolean: req under treatment */
-
- /*
- ** administration to keep track of free space in cowfile filesystem
- */
- unsigned long blksize; /* block size of fs (bytes) */
- unsigned long blktotal; /* recent total space in fs (blocks) */
- unsigned long blkavail; /* recent free space in fs (blocks) */
-
- wait_queue_head_t watchq; /* wait-Q: watcher awaits threshold */
- unsigned long watchthresh; /* threshold of watcher (blocks) */
-
- /*
- ** statistical counters
- */
- unsigned long rdoreads; /* number of read-actions rdo */
- unsigned long cowreads; /* number of read-actions cow */
- unsigned long cowwrites; /* number of write-actions */
- unsigned long nrcowblocks; /* number of blocks in use on cow */
-};
-
-static struct cowloop_device **cowdevall; /* ptr to ptrs to all cowdevices */
-static struct semaphore cowdevlock; /* generic lock for cowdevs */
-
-static struct gendisk *cowctlgd; /* gendisk control channel */
-static spinlock_t cowctlrqlock; /* for req.q. of ctrl. channel */
-
-/*
-** private directory /proc/cow
-*/
-struct proc_dir_entry *cowlo_procdir;
-
-/*
-** function prototypes
-*/
-static long int cowlo_do_request (struct request *req);
-static void cowlo_sync (void);
-static int cowlo_checkio (struct cowloop_device *, int, loff_t);
-static int cowlo_readmix (struct cowloop_device *, void *, int, loff_t);
-static int cowlo_writemix (struct cowloop_device *, void *, int, loff_t);
-static long int cowlo_readrdo (struct cowloop_device *, void *, int, loff_t);
-static long int cowlo_readcow (struct cowloop_device *, void *, int, loff_t);
-static long int cowlo_readcowraw (struct cowloop_device *, void *, int, loff_t);
-static long int cowlo_writecow (struct cowloop_device *, void *, int, loff_t);
-static long int cowlo_writecowraw(struct cowloop_device *, void *, int, loff_t);
-static int cowlo_ioctl (struct block_device *, fmode_t,
- unsigned int, unsigned long);
-static int cowlo_makepair (struct cowpair __user *);
-static int cowlo_removepair (unsigned long __user *);
-static int cowlo_watch (struct cowpair __user *);
-static int cowlo_cowctl (unsigned long __user *, int);
-static int cowlo_openpair (char *, char *, int, int);
-static int cowlo_closepair (struct cowloop_device *);
-static int cowlo_openrdo (struct cowloop_device *, char *);
-static int cowlo_opencow (struct cowloop_device *, char *, int);
-static void cowlo_undo_openrdo(struct cowloop_device *);
-static void cowlo_undo_opencow(struct cowloop_device *);
-
-/*****************************************************************************/
-/* System call handling */
-/*****************************************************************************/
-
-/*
-** handle system call open()/mount()
-**
-** returns:
-** 0 - okay
-** < 0 - error value
-*/
-static int cowlo_open(struct block_device *bdev, fmode_t mode)
-{
- struct inode *inode = bdev->bd_inode;
-
- if (!inode)
- return -EINVAL;
-
- if (imajor(inode) != COWMAJOR) {
- printk(KERN_WARNING
- "cowloop - unexpected major %d\n", imajor(inode));
- return -ENODEV;
- }
-
- switch (iminor(inode)) {
- case COWCTL:
- DEBUGP(DCOW"cowloop - open %d control\n", COWCTL);
- break;
-
- default:
- DEBUGP(DCOW"cowloop - open minor %d\n", iminor(inode));
-
- if ( iminor(inode) >= maxcows )
- return -ENODEV;
-
- if ( !((cowdevall[iminor(inode)])->state & COWDEVOPEN) )
- return -ENODEV;
-
- (cowdevall[iminor(inode)])->opencnt++;
- }
-
- return 0;
-}
-
-/*
-** handle system call close()/umount()
-**
-** returns:
-** 0 - okay
-*/
-static int cowlo_release(struct gendisk *gd, fmode_t mode)
-{
- struct block_device *bdev;
- struct inode *inode;
-
- bdev = bdget_disk(gd, 0);
- inode = bdev->bd_inode;
- if (!inode)
- return 0;
-
- DEBUGP(DCOW"cowloop - release (close) minor %d\n", iminor(inode));
-
- if ( iminor(inode) != COWCTL)
- (cowdevall[iminor(inode)])->opencnt--;
-
- return 0;
-}
-
-/*
-** handle system call ioctl()
-**
-** returns:
-** 0 - okay
-** < 0 - error value
-*/
-static int cowlo_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- struct hd_geometry geo;
- struct inode *inode = bdev->bd_inode;
-
- DEBUGP(DCOW "cowloop - ioctl cmd %x\n", cmd);
-
- switch ( iminor(inode) ) {
-
- /*
- ** allowed via control device only
- */
- case COWCTL:
- switch (cmd) {
- /*
- ** write all bitmap chunks and cowheaders to cowfiles
- */
- case COWSYNC:
- down(&cowdevlock);
- cowlo_sync();
- up(&cowdevlock);
- return 0;
-
- /*
- ** open a new cowdevice (pair of rdofile/cowfile)
- */
- case COWMKPAIR:
- return cowlo_makepair((void __user *)arg);
-
- /*
- ** close a cowdevice (pair of rdofile/cowfile)
- */
- case COWRMPAIR:
- return cowlo_removepair((void __user *)arg);
-
- /*
- ** watch free space of filesystem containing cowfile
- */
- case COWWATCH:
- return cowlo_watch((void __user *)arg);
-
- /*
- ** close cowfile for active device
- */
- case COWCLOSE:
- return cowlo_cowctl((void __user *)arg, COWCLOSE);
-
- /*
- ** reopen cowfile read-only for active device
- */
- case COWRDOPEN:
- return cowlo_cowctl((void __user *)arg, COWRDOPEN);
-
- default:
- return -EINVAL;
- } /* end of switch on command */
-
- /*
- ** allowed for any other cowdevice
- */
- default:
- switch (cmd) {
- /*
- ** HDIO_GETGEO must be supported for fdisk, etc
- */
- case HDIO_GETGEO:
- geo.cylinders = 0;
- geo.heads = 0;
- geo.sectors = 0;
-
- if (copy_to_user((void __user *)arg, &geo, sizeof geo))
- return -EFAULT;
- return 0;
-
- default:
- return -EINVAL;
- } /* end of switch on ioctl-cmd code parameter */
- } /* end of switch on minor number */
-}
-
-static struct block_device_operations cowlo_fops =
-{
- .owner = THIS_MODULE,
- .open = cowlo_open, /* called upon open */
- .release = cowlo_release, /* called upon close */
- .ioctl = cowlo_ioctl, /* called upon ioctl */
-};
-
-/*
-** handle ioctl-command COWMKPAIR:
-** open a new cowdevice (pair of rdofile/cowfile) on-the-fly
-**
-** returns:
-** 0 - okay
-** < 0 - error value
-*/
-static int
-cowlo_makepair(struct cowpair __user *arg)
-{
- int i, rv=0;
- struct cowpair cowpair;
- unsigned char *cowpath;
- unsigned char *rdopath;
-
- /*
- ** retrieve info about pathnames
- */
- if ( copy_from_user(&cowpair, arg, sizeof cowpair) )
- return -EFAULT;
-
- if ( (MAJOR(cowpair.device) != COWMAJOR) && (cowpair.device != ANYDEV) )
- return -EINVAL;
-
- if ( (MINOR(cowpair.device) >= maxcows) && (cowpair.device != ANYDEV) )
- return -EINVAL;
-
- /*
- ** retrieve pathname strings
- */
- if ( (cowpair.cowflen > PATH_MAX) || (cowpair.rdoflen > PATH_MAX) )
- return -ENAMETOOLONG;
-
- if ( !(cowpath = kmalloc(cowpair.cowflen+1, GFP_KERNEL)) )
- return -ENOMEM;
-
- if ( copy_from_user(cowpath, (void __user *)cowpair.cowfile,
- cowpair.cowflen) ) {
- kfree(cowpath);
- return -EFAULT;
- }
- *(cowpath+cowpair.cowflen) = 0;
-
- if ( !(rdopath = kmalloc(cowpair.rdoflen+1, GFP_KERNEL)) ) {
- kfree(cowpath);
- return -ENOMEM;
- }
-
- if ( copy_from_user(rdopath, (void __user *)cowpair.rdofile,
- cowpair.rdoflen) ) {
- kfree(rdopath);
- kfree(cowpath);
- return -EFAULT;
- }
- *(rdopath+cowpair.rdoflen) = 0;
-
- /*
- ** open new cowdevice
- */
- if ( cowpair.device == ANYDEV) {
- /*
- ** search first unused minor
- */
- for (i=0, rv=-EBUSY; i < maxcows; i++) {
- if ( !((cowdevall[i])->state & COWDEVOPEN) ) {
- rv = cowlo_openpair(rdopath, cowpath, 0, i);
- break;
- }
- }
-
- if (rv) { /* open failed? */
- kfree(rdopath);
- kfree(cowpath);
- return rv;
- }
-
- /*
- ** return newly allocated cowdevice to user space
- */
- cowpair.device = MKDEV(COWMAJOR, i);
-
- if ( copy_to_user(arg, &cowpair, sizeof cowpair)) {
- kfree(rdopath);
- kfree(cowpath);
- return -EFAULT;
- }
- } else { /* specific minor requested */
- if ( (rv = cowlo_openpair(rdopath, cowpath, 0,
- MINOR(cowpair.device)))) {
- kfree(rdopath);
- kfree(cowpath);
- return rv;
- }
- }
-
- return 0;
-}
-
-/*
-** handle ioctl-command COWRMPAIR:
-** deactivate an existing cowdevice (pair of rdofile/cowfile) on-the-fly
-**
-** returns:
-** 0 - okay
-** < 0 - error value
-*/
-static int
-cowlo_removepair(unsigned long __user *arg)
-{
- unsigned long cowdevice;
- struct cowloop_device *cowdev;
-
- /*
- ** retrieve info about device to be removed
- */
- if ( copy_from_user(&cowdevice, arg, sizeof cowdevice))
- return -EFAULT;
-
- /*
- ** verify major-minor number
- */
- if ( MAJOR(cowdevice) != COWMAJOR)
- return -EINVAL;
-
- if ( MINOR(cowdevice) >= maxcows)
- return -EINVAL;
-
- cowdev = cowdevall[MINOR(cowdevice)];
-
- if ( !(cowdev->state & COWDEVOPEN) )
- return -ENODEV;
-
- /*
- ** synchronize bitmaps and close cowdevice
- */
- if (cowdev->state & COWRWCOWOPEN) {
- down(&cowdevlock);
- cowlo_sync();
- up(&cowdevlock);
- }
-
- return cowlo_closepair(cowdev);
-}
-
-/*
-** handle ioctl-command COWWATCH:
-** watch the free space of the filesystem containing a cowfile
-** of an open cowdevice
-**
-** returns:
-** 0 - okay
-** < 0 - error value
-*/
-static int
-cowlo_watch(struct cowpair __user *arg)
-{
- struct cowloop_device *cowdev;
- struct cowwatch cowwatch;
-
- /*
- ** retrieve structure holding info
- */
- if ( copy_from_user(&cowwatch, arg, sizeof cowwatch))
- return -EFAULT;
-
- /*
- ** verify if cowdevice exists and is currently open
- */
- if ( MINOR(cowwatch.device) >= maxcows)
- return -EINVAL;
-
- cowdev = cowdevall[MINOR(cowwatch.device)];
-
- if ( !(cowdev->state & COWDEVOPEN) )
- return -ENODEV;
-
- /*
- ** if the WATCHWAIT-option is set, wait until the indicated
- ** threshold is reached (only one waiter allowed)
- */
- if (cowwatch.flags & WATCHWAIT) {
- /*
- ** check if already another waiter active
- ** for this cowdevice
- */
- if (cowdev->state & COWWATCHDOG)
- return -EAGAIN;
-
- cowdev->state |= COWWATCHDOG;
-
- cowdev->watchthresh = (unsigned long long)
- cowwatch.threshold /
- (cowdev->blksize / 1024);
-
- if (wait_event_interruptible(cowdev->watchq,
- cowdev->watchthresh >= cowdev->blkavail)) {
- cowdev->state &= ~COWWATCHDOG;
- return EINTR;
- }
-
- cowdev->state &= ~COWWATCHDOG;
- }
-
- cowwatch.totalkb = (unsigned long long)cowdev->blktotal *
- cowdev->blksize / 1024;
- cowwatch.availkb = (unsigned long long)cowdev->blkavail *
- cowdev->blksize / 1024;
-
- if ( copy_to_user(arg, &cowwatch, sizeof cowwatch))
- return -EFAULT;
-
- return 0;
-}
-
-/*
-** handle ioctl-commands COWCLOSE and COWRDOPEN:
-** COWCLOSE - close the cowfile while the cowdevice remains open;
-** this allows an unmount of the filesystem on which
-** the cowfile resides
-** COWRDOPEN - close the cowfile and reopen it for read-only;
-** this allows a remount read-ony of the filesystem
-** on which the cowfile resides
-**
-** returns:
-** 0 - okay
-** < 0 - error value
-*/
-static int
-cowlo_cowctl(unsigned long __user *arg, int cmd)
-{
- struct cowloop_device *cowdev;
- unsigned long cowdevice;
-
- /*
- ** retrieve info about device to be removed
- */
- if ( copy_from_user(&cowdevice, arg, sizeof cowdevice))
- return -EFAULT;
-
- /*
- ** verify major-minor number
- */
- if ( MAJOR(cowdevice) != COWMAJOR)
- return -EINVAL;
-
- if ( MINOR(cowdevice) >= maxcows)
- return -EINVAL;
-
- cowdev = cowdevall[MINOR(cowdevice)];
-
- if ( !(cowdev->state & COWDEVOPEN) )
- return -ENODEV;
-
- /*
- ** synchronize bitmaps and close cowfile
- */
- if (cowdev->state & COWRWCOWOPEN) {
- down(&cowdevlock);
- cowlo_sync();
- up(&cowdevlock);
- }
-
- /*
- ** handle specific ioctl-command
- */
- switch (cmd) {
- case COWRDOPEN:
- /*
- ** if the cowfile is still opened read-write
- */
- if (cowdev->state & COWRWCOWOPEN) {
- /*
- ** close the cowfile
- */
- if (cowdev->cowfp)
- filp_close(cowdev->cowfp, 0);
-
- cowdev->state &= ~COWRWCOWOPEN;
-
- /*
- ** open again for read-only
- */
- cowdev->cowfp = filp_open(cowdev->cowname,
- O_RDONLY|O_LARGEFILE, 0600);
-
- if ( (cowdev->cowfp == NULL) || IS_ERR(cowdev->cowfp) ) {
- printk(KERN_ERR
- "cowloop - failed to reopen cowfile %s\n",
- cowdev->cowname);
- return -EINVAL;
- }
-
- /*
- ** mark cowfile open for read-only
- */
- cowdev->state |= COWRDCOWOPEN;
- } else {
- return -EINVAL;
- }
- break;
-
- case COWCLOSE:
- /*
- ** if the cowfile is still open
- */
- if (cowdev->state & COWCOWOPEN) {
- /*
- ** close the cowfile
- */
- if (cowdev->cowfp)
- filp_close(cowdev->cowfp, 0);
-
- cowdev->state &= ~COWCOWOPEN;
- }
- }
-
- return 0;
-}
-
-
-/*****************************************************************************/
-/* Handling of I/O-requests for a cowdevice */
-/*****************************************************************************/
-
-/*
-** function to be called by core-kernel to handle the I/O-requests
-** in the queue
-*/
-static void cowlo_request(struct request_queue *q)
-{
- struct request *req;
- struct cowloop_device *cowdev;
-
- DEBUGP(DCOW "cowloop - request function called....\n");
-
- while((req = blk_peek_request(q)) != NULL) {
- DEBUGP(DCOW "cowloop - got next request\n");
-
- if (! blk_fs_request(req)) {
- /* this is not a normal file system request */
- __blk_end_request_cur(req, -EIO);
- continue;
- }
- cowdev = req->rq_disk->private_data;
-
- if (cowdev->iobusy)
- return;
- else
- cowdev->iobusy = 1;
-
- /*
- ** when no kernel-thread is available, the request will
- ** produce an I/O-error
- */
- if (!cowdev->pid) {
- printk(KERN_ERR"cowloop - no thread available\n");
- __blk_end_request_cur(req, -EIO); /* request failed */
- cowdev->iobusy = 0;
- continue;
- }
-
- /*
- ** handle I/O-request in the context of the kernel-thread
- */
- cowdev->req = req;
- cowdev->qfilled = 1;
-
- wake_up_interruptible_sync(&cowdev->waitq);
-
- /*
- ** get out of this function now while the I/O-request is
- ** under treatment of the kernel-thread; this function
- ** will be called again after the current I/O-request has
- ** been finished by the thread
- */
- return;
- }
-}
-
-/*
-** daemon-process (kernel-thread) executes this function
-*/
-static int
-cowlo_daemon(struct cowloop_device *cowdev)
-{
- int rv;
- int minor;
- char myname[16];
-
- for (minor = 0; minor < maxcows; minor++) {
- if (cowdev == cowdevall[minor]) break;
- }
- sprintf(myname, "cowloopd%d", minor);
-
- daemonize(myname);
-
- while (!cowdev->closedown) {
- /*
- ** sleep while waiting for an I/O request;
- ** note that no non-interruptible wait has been used
- ** because the non-interruptible version of
- ** a *synchronous* wake_up does not exist (any more)
- */
- if (wait_event_interruptible(cowdev->waitq, cowdev->qfilled)){
- flush_signals(current); /* ignore signal-based wakeup */
- continue;
- }
-
- if (cowdev->closedown) /* module will be unloaded ? */{
- cowdev->pid = 0;
- return 0;
- }
-
- /*
- ** woken up by the I/O-request handler: treat requested I/O
- */
- cowdev->qfilled = 0;
-
- rv = cowlo_do_request(cowdev->req);
-
- /*
- ** reacquire the queue-spinlock for manipulating
- ** the request-queue and dequeue the request
- */
- spin_lock_irq(&cowdev->rqlock);
-
- __blk_end_request_cur(cowdev->req, rv);
- cowdev->iobusy = 0;
-
- /*
- ** initiate the next request from the queue
- */
- cowlo_request(cowdev->rqueue);
-
- spin_unlock_irq(&cowdev->rqlock);
- }
- return 0;
-}
-
-/*
-** function to be called in the context of the kernel thread
-** to handle the queued I/O-requests
-**
-** returns:
-** 0 - fail
-** 1 - success
-*/
-static long int
-cowlo_do_request(struct request *req)
-{
- unsigned long len;
- long int rv;
- loff_t offset;
- struct cowloop_device *cowdev = req->rq_disk->private_data;
-
- /*
- ** calculate some variables which are needed later on
- */
- len = blk_rq_cur_sectors(req) << 9;
- offset = (loff_t) blk_rq_pos(req) << 9;
-
- DEBUGP(DCOW"cowloop - req cmd=%d offset=%lld len=%lu addr=%p\n",
- *(req->cmd), offset, len, req->buffer);
-
- /*
- ** handle READ- or WRITE-request
- */
- switch (rq_data_dir(req)) {
- /**********************************************************/
- case READ:
- switch ( cowlo_checkio(cowdev, len, offset) ) {
- case ALLCOW:
- rv = cowlo_readcow(cowdev, req->buffer, len, offset);
- break;
-
- case ALLRDO:
- rv = cowlo_readrdo(cowdev, req->buffer, len, offset);
- break;
-
- case MIXEDUP:
- rv = cowlo_readmix(cowdev, req->buffer, len, offset);
- break;
-
- default:
- rv = 0; /* never happens */
- }
- break;
-
- /**********************************************************/
- case WRITE:
- switch ( cowlo_checkio(cowdev, len, offset) ) {
- case ALLCOW:
- /*
- ** straight-forward write will do...
- */
- DEBUGP(DCOW"cowloop - write straight ");
-
- rv = cowlo_writecow(cowdev, req->buffer, len, offset);
- break; /* from switch */
-
- case ALLRDO:
- if ( (len & MUMASK) == 0) {
- DEBUGP(DCOW"cowloop - write straight ");
-
- rv = cowlo_writecow(cowdev, req->buffer,
- len, offset);
- break;
- }
-
- case MIXEDUP:
- rv = cowlo_writemix(cowdev, req->buffer, len, offset);
- break;
-
- default:
- rv = 0; /* never happens */
- }
- break;
-
- default:
- printk(KERN_ERR
- "cowloop - unrecognized command %d\n", *(req->cmd));
- rv = 0;
- }
-
- return (rv <= 0 ? 0 : 1);
-}
-
-/*
-** check for a given I/O-request if all underlying blocks
-** (with size MAPUNIT) are either in the read-only file or in
-** the cowfile (or a combination of the two)
-**
-** returns:
-** ALLRDO - all underlying blocks in rdofile
-** ALLCOW - all underlying blocks in cowfile
-** MIXEDUP - underlying blocks partly in rdofile and partly in cowfile
-*/
-static int
-cowlo_checkio(struct cowloop_device *cowdev, int len, loff_t offset)
-{
- unsigned long mapnum, bytenum, bitnum, blocknr, partlen;
- long int totcnt, cowcnt;
- char *mc;
-
- /*
- ** notice that the requested block might cross
- ** a blocksize boundary while one of the concerned
- ** blocks resides in the read-only file and another
- ** one in the copy-on-write file; in that case the
- ** request will be broken up into pieces
- */
- if ( (len <= MAPUNIT) &&
- (MAPUNIT - (offset & MUMASK) <= len) ) {
- /*
- ** easy situation:
- ** requested data-block entirely fits within
- ** the mapunit used for the bitmap
- ** check if that block is located in rdofile or
- ** cowfile
- */
- blocknr = offset >> MUSHIFT;
-
- mapnum = CALCMAP (blocknr);
- bytenum = CALCBYTE(blocknr);
- bitnum = CALCBIT (blocknr);
-
- if (*(*(cowdev->mapcache+mapnum)+bytenum)&(1<<bitnum))
- return ALLCOW;
- else
- return ALLRDO;
- }
-
- /*
- ** less easy situation:
- ** the requested data-block does not fit within the mapunit
- ** used for the bitmap
- ** check if *all* underlying blocks involved reside on the rdofile
- ** or the cowfile (so still no breakup required)
- */
- for (cowcnt=totcnt=0; len > 0; len-=partlen, offset+=partlen, totcnt++){
- /*
- ** calculate blocknr of involved block
- */
- blocknr = offset >> MUSHIFT;
-
- /*
- ** calculate partial length for this transfer
- */
- partlen = MAPUNIT - (offset & MUMASK);
- if (partlen > len)
- partlen = len;
-
- /*
- ** is this block located in the cowfile
- */
- mapnum = CALCMAP (blocknr);
- bytenum = CALCBYTE(blocknr);
- bitnum = CALCBIT (blocknr);
-
- mc = *(cowdev->mapcache+mapnum);
-
- if (*(mc+bytenum)&(1<<bitnum))
- cowcnt++;;
-
- DEBUGP(DCOW
- "cowloop - check %lu - map %lu, byte %lu, bit %lu, "
- "cowcnt %ld, totcnt %ld %02x %p\n",
- blocknr, mapnum, bytenum, bitnum, cowcnt, totcnt,
- *(mc+bytenum), mc);
- }
-
- if (cowcnt == 0) /* all involved blocks on rdofile? */
- return ALLRDO;
-
- if (cowcnt == totcnt) /* all involved blocks on cowfile? */
- return ALLCOW;
-
- /*
- ** situation somewhat more complicated:
- ** involved underlying blocks spread over both files
- */
- return MIXEDUP;
-}
-
-/*
-** read requested chunk partly from rdofile and partly from cowfile
-**
-** returns:
-** 0 - fail
-** 1 - success
-*/
-static int
-cowlo_readmix(struct cowloop_device *cowdev, void *buf, int len, loff_t offset)
-{
- unsigned long mapnum, bytenum, bitnum, blocknr, partlen;
- long int rv;
- char *mc;
-
- /*
- ** complicated approach: breakup required of read-request
- */
- for (rv=1; len > 0; len-=partlen, buf+=partlen, offset+=partlen) {
- /*
- ** calculate blocknr of entire block
- */
- blocknr = offset >> MUSHIFT;
-
- /*
- ** calculate partial length for this transfer
- */
- partlen = MAPUNIT - (offset & MUMASK);
- if (partlen > len)
- partlen = len;
-
- /*
- ** is this block located in the cowfile
- */
- mapnum = CALCMAP (blocknr);
- bytenum = CALCBYTE(blocknr);
- bitnum = CALCBIT (blocknr);
- mc = *(cowdev->mapcache+mapnum);
-
- if (*(mc+bytenum)&(1<<bitnum)) {
- /*
- ** read (partial) block from cowfile
- */
- DEBUGP(DCOW"cowloop - split read "
- "cow partlen=%ld off=%lld\n", partlen, offset);
-
- if (cowlo_readcow(cowdev, buf, partlen, offset) <= 0)
- rv = 0;
- } else {
- /*
- ** read (partial) block from rdofile
- */
- DEBUGP(DCOW"cowloop - split read "
- "rdo partlen=%ld off=%lld\n", partlen, offset);
-
- if (cowlo_readrdo(cowdev, buf, partlen, offset) <= 0)
- rv = 0;
- }
- }
-
- return rv;
-}
-
-/*
-** chunk to be written to the cowfile needs pieces to be
-** read from the rdofile
-**
-** returns:
-** 0 - fail
-** 1 - success
-*/
-static int
-cowlo_writemix(struct cowloop_device *cowdev, void *buf, int len, loff_t offset)
-{
- unsigned long mapnum, bytenum, bitnum, blocknr, partlen;
- long int rv;
- char *mc;
-
- /*
- ** somewhat more complicated stuff is required:
- ** if the request is larger than one underlying
- ** block or is spread over two underlying blocks,
- ** split the request into pieces; if a block does not
- ** start at a block boundary, take care that
- ** surrounding data is read first (if needed),
- ** fit the new data in and write it as a full block
- */
- for (rv=1; len > 0; len-=partlen, buf+=partlen, offset+=partlen) {
- /*
- ** calculate partial length for this transfer
- */
- partlen = MAPUNIT - (offset & MUMASK);
- if (partlen > len)
- partlen = len;
-
- /*
- ** calculate blocknr of entire block
- */
- blocknr = offset >> MUSHIFT;
-
- /*
- ** has this block been written before?
- */
- mapnum = CALCMAP (blocknr);
- bytenum = CALCBYTE(blocknr);
- bitnum = CALCBIT (blocknr);
- mc = *(cowdev->mapcache+mapnum);
-
- if (*(mc+bytenum)&(1<<bitnum)) {
- /*
- ** block has been written before;
- ** write transparantly to cowfile
- */
- DEBUGP(DCOW
- "cowloop - splitwr transp\n");
-
- if (cowlo_writecow(cowdev, buf, partlen, offset) <= 0)
- rv = 0;
- } else {
- /*
- ** block has never been written before,
- ** so read entire block from
- ** read-only file first, unless
- ** a full block is requested to
- ** be written
- */
- if (partlen < MAPUNIT) {
- if (cowlo_readrdo(cowdev, cowdev->iobuf,
- MAPUNIT, (loff_t)blocknr << MUSHIFT) <= 0)
- rv = 0;
- }
-
- /*
- ** transfer modified part into
- ** the block just read
- */
- memcpy(cowdev->iobuf + (offset & MUMASK), buf, partlen);
-
- /*
- ** write entire block to cowfile
- */
- DEBUGP(DCOW"cowloop - split "
- "partlen=%ld off=%lld\n",
- partlen, (loff_t)blocknr << MUSHIFT);
-
- if (cowlo_writecow(cowdev, cowdev->iobuf, MAPUNIT,
- (loff_t)blocknr << MUSHIFT) <= 0)
- rv = 0;
- }
- }
-
- return rv;
-}
-
-/*****************************************************************************/
-/* I/O-support for read-only file and copy-on-write file */
-/*****************************************************************************/
-
-/*
-** read data from the read-only file
-**
-** return-value: similar to user-mode read
-*/
-static long int
-cowlo_readrdo(struct cowloop_device *cowdev, void *buf, int len, loff_t offset)
-{
- long int rv;
- mm_segment_t old_fs;
- loff_t saveoffset = offset;
-
- DEBUGP(DCOW"cowloop - readrdo called\n");
-
- old_fs = get_fs();
- set_fs( get_ds() );
- rv = cowdev->rdofp->f_op->read(cowdev->rdofp, buf, len, &offset);
- set_fs(old_fs);
-
- if (rv < len) {
- printk(KERN_WARNING "cowloop - read-failure %ld on rdofile"
- "- offset=%lld len=%d\n",
- rv, saveoffset, len);
- }
-
- cowdev->rdoreads++;
- return rv;
-}
-
-/*
-** read cowfile from a modified offset, i.e. skipping the bitmap and cowhead
-**
-** return-value: similar to user-mode read
-*/
-static long int
-cowlo_readcow(struct cowloop_device *cowdev, void *buf, int len, loff_t offset)
-{
- DEBUGP(DCOW"cowloop - readcow called\n");
-
- offset += cowdev->cowhead->doffset;
-
- return cowlo_readcowraw(cowdev, buf, len, offset);
-}
-
-/*
-** read cowfile from an absolute offset
-**
-** return-value: similar to user-mode read
-*/
-static long int
-cowlo_readcowraw(struct cowloop_device *cowdev,
- void *buf, int len, loff_t offset)
-{
- long int rv;
- mm_segment_t old_fs;
- loff_t saveoffset = offset;
-
- DEBUGP(DCOW"cowloop - readcowraw called\n");
-
- /*
- ** be sure that cowfile is opened for read-write
- */
- if ( !(cowdev->state & COWCOWOPEN) ) {
- printk(KERN_WARNING
- "cowloop - read request from cowfile refused\n");
-
- return -EBADF;
- }
-
- /*
- ** issue low level read
- */
- old_fs = get_fs();
- set_fs( get_ds() );
- rv = cowdev->cowfp->f_op->read(cowdev->cowfp, buf, len, &offset);
- set_fs(old_fs);
-
- if (rv < len) {
- printk(KERN_WARNING
- "cowloop - read-failure %ld on cowfile"
- "- offset=%lld len=%d\n", rv, saveoffset, len);
- }
-
- cowdev->cowreads++;
- return rv;
-}
-
-/*
-** write cowfile from a modified offset, i.e. skipping the bitmap and cowhead
-**
-** if a block is written for the first time while its contents consists
-** of binary zeroes only, the concerning bitmap is flushed to the cowfile
-**
-** return-value: similar to user-mode write
-*/
-static long int
-cowlo_writecow(struct cowloop_device *cowdev, void *buf, int len, loff_t offset)
-{
- long int rv;
- unsigned long mapnum=0, mapbyte=0, mapbit=0, cowblock=0, partlen;
- char *tmpptr, *mapptr = NULL;
- loff_t tmpoffset, mapoffset = 0;
-
- DEBUGP(DCOW"cowloop - writecow called\n");
-
- /*
- ** be sure that cowfile is opened for read-write
- */
- if ( !(cowdev->state & COWRWCOWOPEN) ) {
- printk(KERN_WARNING
- "cowloop - Write request to cowfile refused\n");
-
- return -EBADF;
- }
-
- /*
- ** write the entire block to the cowfile
- */
- tmpoffset = offset + cowdev->cowhead->doffset;
-
- rv = cowlo_writecowraw(cowdev, buf, len, tmpoffset);
-
- /*
- ** verify if enough space available on filesystem holding
- ** the cowfile
- ** - when the last write failed (might be caused by lack of space)
- ** - when a watcher is active (to react adequatly)
- ** - when the previous check indicated fs was almost full
- ** - with regular intervals
- */
- if ( (rv <= 0) ||
- (cowdev->state & COWWATCHDOG) ||
- (cowdev->blkavail / 2 < SPCDFLINTVL) ||
- (cowdev->cowwrites % SPCDFLINTVL == 0) ) {
- struct kstatfs ks;
-
- if (vfs_statfs(cowdev->cowfp->f_dentry, &ks)==0){
- if (ks.f_bavail <= SPCMINBLK) {
- switch (ks.f_bavail) {
- case 0:
- case 1:
- case 2:
- case 3:
- printk(KERN_ALERT
- "cowloop - "
- "ALERT: cowfile full!\n");
- break;
-
- default:
- printk(KERN_WARNING
- "cowloop - cowfile almost "
- "full (only %llu Kb free)\n",
- (unsigned long long)
- ks.f_bsize * ks.f_bavail /1024);
- }
- }
-
- cowdev->blktotal = ks.f_blocks;
- cowdev->blkavail = ks.f_bavail;
-
- /*
- ** wakeup watcher if threshold has been reached
- */
- if ( (cowdev->state & COWWATCHDOG) &&
- (cowdev->watchthresh >= cowdev->blkavail) ) {
- wake_up_interruptible(&cowdev->watchq);
- }
- }
- }
-
- if (rv <= 0)
- return rv;
-
- DEBUGP(DCOW"cowloop - block written\n");
-
- /*
- ** check if block(s) is/are written to the cowfile
- ** for the first time; if so, adapt the bitmap
- */
- for (; len > 0; len-=partlen, offset+=partlen, buf+=partlen) {
- /*
- ** calculate partial length for this transfer
- */
- partlen = MAPUNIT - (offset & MUMASK);
- if (partlen > len)
- partlen = len;
-
- /*
- ** calculate bitnr of written chunk of cowblock
- */
- cowblock = offset >> MUSHIFT;
-
- mapnum = CALCMAP (cowblock);
- mapbyte = CALCBYTE(cowblock);
- mapbit = CALCBIT (cowblock);
-
- if (*(*(cowdev->mapcache+mapnum)+mapbyte) & (1<<mapbit))
- continue; /* already written before */
-
- /*
- ** if the block is written for the first time,
- ** the corresponding bit should be set in the bitmap
- */
- *(*(cowdev->mapcache+mapnum)+mapbyte) |= (1<<mapbit);
-
- cowdev->nrcowblocks++;
-
- DEBUGP(DCOW"cowloop - bitupdate blk=%ld map=%ld "
- "byte=%ld bit=%ld\n",
- cowblock, mapnum, mapbyte, mapbit);
-
- /*
- ** check if the cowhead in the cowfile is currently
- ** marked clean; if so, mark it dirty and flush it
- */
- if ( !(cowdev->cowhead->flags &= COWDIRTY)) {
- cowdev->cowhead->flags |= COWDIRTY;
-
- cowlo_writecowraw(cowdev, cowdev->cowhead,
- MAPUNIT, (loff_t)0);
- }
-
- /*
- ** if the written datablock contained binary zeroes,
- ** the bitmap block should be marked to be flushed to disk
- ** (blocks containing all zeroes cannot be recovered by
- ** the cowrepair-program later on if cowloop is not properly
- ** removed via rmmod)
- */
- if ( memcmp(buf, allzeroes, partlen) ) /* not all zeroes? */
- continue; /* no flush needed */
-
- /*
- ** calculate positions of bitmap block to be flushed
- ** - pointer of bitmap block in memory
- ** - offset of bitmap block in cowfile
- */
- tmpptr = *(cowdev->mapcache+mapnum) + (mapbyte & (~MUMASK));
- tmpoffset = (loff_t) MAPUNIT + mapnum * MAPCHUNKSZ +
- (mapbyte & (~MUMASK));
-
- /*
- ** flush a bitmap block at the moment that all bits have
- ** been set in that block, i.e. at the moment that we
- ** switch to another bitmap block
- */
- if ( (mapoffset != 0) && (mapoffset != tmpoffset) ) {
- if (cowlo_writecowraw(cowdev, mapptr, MAPUNIT,
- mapoffset) < 0) {
- printk(KERN_WARNING
- "cowloop - write-failure on bitmap - "
- "blk=%ld map=%ld byte=%ld bit=%ld\n",
- cowblock, mapnum, mapbyte, mapbit);
- }
-
- DEBUGP(DCOW"cowloop - bitmap blk written %lld\n",
- mapoffset);
- }
-
- /*
- ** remember offset in cowfile and offset in memory
- ** for bitmap to be flushed; flushing will be done
- ** as soon as all updates in this bitmap block have
- ** been done
- */
- mapoffset = tmpoffset;
- mapptr = tmpptr;
- }
-
- /*
- ** any new block written containing binary zeroes?
- */
- if (mapoffset) {
- if (cowlo_writecowraw(cowdev, mapptr, MAPUNIT, mapoffset) < 0) {
- printk(KERN_WARNING
- "cowloop - write-failure on bitmap - "
- "blk=%ld map=%ld byte=%ld bit=%ld\n",
- cowblock, mapnum, mapbyte, mapbit);
- }
-
- DEBUGP(DCOW"cowloop - bitmap block written %lld\n", mapoffset);
- }
-
- return rv;
-}
-
-/*
-** write cowfile from an absolute offset
-**
-** return-value: similar to user-mode write
-*/
-static long int
-cowlo_writecowraw(struct cowloop_device *cowdev,
- void *buf, int len, loff_t offset)
-{
- long int rv;
- mm_segment_t old_fs;
- loff_t saveoffset = offset;
-
- DEBUGP(DCOW"cowloop - writecowraw called\n");
-
- /*
- ** be sure that cowfile is opened for read-write
- */
- if ( !(cowdev->state & COWRWCOWOPEN) ) {
- printk(KERN_WARNING
- "cowloop - write request to cowfile refused\n");
-
- return -EBADF;
- }
-
- /*
- ** issue low level write
- */
- old_fs = get_fs();
- set_fs( get_ds() );
- rv = cowdev->cowfp->f_op->write(cowdev->cowfp, buf, len, &offset);
- set_fs(old_fs);
-
- if (rv < len) {
- printk(KERN_WARNING
- "cowloop - write-failure %ld on cowfile"
- "- offset=%lld len=%d\n", rv, saveoffset, len);
- }
-
- cowdev->cowwrites++;
- return rv;
-}
-
-
-/*
-** readproc-function: called when the corresponding /proc-file is read
-*/
-static int
-cowlo_readproc(char *buf, char **start, off_t pos, int cnt, int *eof, void *p)
-{
- struct cowloop_device *cowdev = p;
-
- revision[sizeof revision - 3] = '\0';
-
- return sprintf(buf,
- " cowloop version: %9s\n\n"
- " device state: %s%s%s%s\n"
- " number of opens: %9d\n"
- " pid of thread: %9d\n\n"
- " read-only file: %9s\n"
- " rdoreads: %9lu\n\n"
- "copy-on-write file: %9s\n"
- " state cowfile: %9s\n"
- " bitmap-blocks: %9lu (of %d bytes)\n"
- " cowblocks in use: %9lu (of %d bytes)\n"
- " cowreads: %9lu\n"
- " cowwrites: %9lu\n",
- &revision[11],
-
- cowdev->state & COWDEVOPEN ? "devopen " : "",
- cowdev->state & COWRWCOWOPEN ? "cowopenrw " : "",
- cowdev->state & COWRDCOWOPEN ? "cowopenro " : "",
- cowdev->state & COWWATCHDOG ? "watchdog " : "",
-
- cowdev->opencnt,
- cowdev->pid,
- cowdev->rdoname,
- cowdev->rdoreads,
- cowdev->cowname,
- cowdev->cowhead->flags & COWDIRTY ? "dirty":"clean",
- cowdev->mapsize >> MUSHIFT, MAPUNIT,
- cowdev->nrcowblocks, MAPUNIT,
- cowdev->cowreads,
- cowdev->cowwrites);
-}
-
-/*****************************************************************************/
-/* Setup and destroy cowdevices */
-/*****************************************************************************/
-
-/*
-** open and prepare a cowdevice (rdofile and cowfile) and allocate bitmaps
-**
-** returns:
-** 0 - okay
-** < 0 - error value
-*/
-static int
-cowlo_openpair(char *rdof, char *cowf, int autorecover, int minor)
-{
- long int rv;
- struct cowloop_device *cowdev = cowdevall[minor];
- struct kstatfs ks;
-
- down(&cowdevlock);
-
- /*
- ** requested device exists?
- */
- if (minor >= maxcows) {
- up(&cowdevlock);
- return -ENODEV;
- }
-
- /*
- ** requested device already assigned to cowdevice?
- */
- if (cowdev->state & COWDEVOPEN) {
- up(&cowdevlock);
- return -EBUSY;
- }
-
- /*
- ** initialize administration
- */
- memset(cowdev, 0, sizeof *cowdev);
-
- spin_lock_init (&cowdev->rqlock);
- init_waitqueue_head(&cowdev->waitq);
- init_waitqueue_head(&cowdev->watchq);
-
- /*
- ** open the read-only file
- */
- DEBUGP(DCOW"cowloop - call openrdo....\n");
-
- if ( (rv = cowlo_openrdo(cowdev, rdof)) ) {
- cowlo_undo_openrdo(cowdev);
- up(&cowdevlock);
- return rv;
- }
-
- /*
- ** open the cowfile
- */
- DEBUGP(DCOW"cowloop - call opencow....\n");
-
- if ( (rv = cowlo_opencow(cowdev, cowf, autorecover)) ) {
- cowlo_undo_openrdo(cowdev);
- cowlo_undo_opencow(cowdev);
- up(&cowdevlock);
- return rv;
- }
-
- /*
- ** administer total and available size of filesystem holding cowfile
- */
- if (vfs_statfs(cowdev->cowfp->f_dentry, &ks)==0) {
- cowdev->blksize = ks.f_bsize;
- cowdev->blktotal = ks.f_blocks;
- cowdev->blkavail = ks.f_bavail;
- } else {
- cowdev->blksize = 1024; /* avoid division by zero */
- }
-
- /*
- ** flush the (recovered) bitmaps and cowhead to the cowfile
- */
- DEBUGP(DCOW"cowloop - call cowsync....\n");
-
- cowlo_sync();
-
- /*
- ** allocate gendisk for the cow device
- */
- DEBUGP(DCOW"cowloop - alloc disk....\n");
-
- if ((cowdev->gd = alloc_disk(1)) == NULL) {
- printk(KERN_WARNING
- "cowloop - unable to alloc_disk for cowloop\n");
-
- cowlo_undo_openrdo(cowdev);
- cowlo_undo_opencow(cowdev);
- up(&cowdevlock);
- return -ENOMEM;
- }
-
- cowdev->gd->major = COWMAJOR;
- cowdev->gd->first_minor = minor;
- cowdev->gd->minors = 1;
- cowdev->gd->fops = &cowlo_fops;
- cowdev->gd->private_data = cowdev;
- sprintf(cowdev->gd->disk_name, "%s%d", DEVICE_NAME, minor);
-
- /* in .5 Kb units */
- set_capacity(cowdev->gd, (cowdev->numblocks*(MAPUNIT/512)));
-
- DEBUGP(DCOW"cowloop - init request queue....\n");
-
- if ((cowdev->rqueue = blk_init_queue(cowlo_request, &cowdev->rqlock))
- == NULL) {
- printk(KERN_WARNING
- "cowloop - unable to get request queue for cowloop\n");
-
- del_gendisk(cowdev->gd);
- cowlo_undo_openrdo(cowdev);
- cowlo_undo_opencow(cowdev);
- up(&cowdevlock);
- return -EINVAL;
- }
-
- blk_queue_logical_block_size(cowdev->rqueue, cowdev->blocksz);
- cowdev->gd->queue = cowdev->rqueue;
-
- /*
- ** start kernel thread to handle requests
- */
- DEBUGP(DCOW"cowloop - kickoff daemon....\n");
-
- cowdev->pid = kernel_thread((int (*)(void *))cowlo_daemon, cowdev, 0);
-
- /*
- ** create a file below directory /proc/cow for this new cowdevice
- */
- if (cowlo_procdir) {
- char tmpname[64];
-
- sprintf(tmpname, "%d", minor);
-
- create_proc_read_entry(tmpname, 0 , cowlo_procdir,
- cowlo_readproc, cowdev);
- }
-
- cowdev->state |= COWDEVOPEN;
-
- cowdev->rdoname = rdof;
- cowdev->cowname = cowf;
-
- /*
- ** enable the new disk; this triggers the first request!
- */
- DEBUGP(DCOW"cowloop - call add_disk....\n");
-
- add_disk(cowdev->gd);
-
- up(&cowdevlock);
- return 0;
-}
-
-/*
-** close a cowdevice (pair of rdofile/cowfile) and release memory
-**
-** returns:
-** 0 - okay
-** < 0 - error value
-*/
-static int
-cowlo_closepair(struct cowloop_device *cowdev)
-{
- int minor;
-
- down(&cowdevlock);
-
- /*
- ** if cowdevice is not activated at all, refuse
- */
- if ( !(cowdev->state & COWDEVOPEN) ) {
- up(&cowdevlock);
- return -ENODEV;
- }
-
- /*
- ** if this cowdevice is still open, refuse
- */
- if (cowdev->opencnt > 0) {
- up(&cowdevlock);
- return -EBUSY;
- }
-
- up(&cowdevlock);
-
- /*
- ** wakeup watcher (if any)
- */
- if (cowdev->state & COWWATCHDOG) {
- cowdev->watchthresh = cowdev->blkavail;
- wake_up_interruptible(&cowdev->watchq);
- }
-
- /*
- ** wakeup kernel-thread to be able to exit
- ** and wait until it has exited
- */
- cowdev->closedown = 1;
- cowdev->qfilled = 1;
- wake_up_interruptible(&cowdev->waitq);
-
- while (cowdev->pid)
- schedule();
-
- del_gendisk(cowdev->gd); /* revert the alloc_disk() */
- put_disk(cowdev->gd); /* revert the add_disk() */
-
- if (cowlo_procdir) {
- char tmpname[64];
-
- for (minor = 0; minor < maxcows; minor++) {
- if (cowdev == cowdevall[minor]) break;
- }
- sprintf(tmpname, "%d", minor);
-
- remove_proc_entry(tmpname, cowlo_procdir);
- }
-
- blk_cleanup_queue(cowdev->rqueue);
-
- /*
- ** release memory for filenames if these names have
- ** been allocated dynamically
- */
- if ( (cowdev->cowname) && (cowdev->cowname != cowfile))
- kfree(cowdev->cowname);
-
- if ( (cowdev->rdoname) && (cowdev->rdoname != rdofile))
- kfree(cowdev->rdoname);
-
- cowlo_undo_openrdo(cowdev);
- cowlo_undo_opencow(cowdev);
-
- cowdev->state &= ~COWDEVOPEN;
-
- return 0;
-}
-
-/*
-** open the read-only file
-**
-** returns:
-** 0 - okay
-** < 0 - error value
-*/
-static int
-cowlo_openrdo(struct cowloop_device *cowdev, char *rdof)
-{
- struct file *f;
- struct inode *inode;
- long int i, nrval;
-
- DEBUGP(DCOW"cowloop - openrdo called\n");
-
- /*
- ** open the read-only file
- */
- if(*rdof == '\0') {
- printk(KERN_ERR
- "cowloop - specify name for read-only file\n\n");
- return -EINVAL;
- }
-
- f = filp_open(rdof, O_RDONLY|O_LARGEFILE, 0);
-
- if ( (f == NULL) || IS_ERR(f) ) {
- printk(KERN_ERR
- "cowloop - open of rdofile %s failed\n", rdof);
- return -EINVAL;
- }
-
- cowdev->rdofp = f;
-
- inode = f->f_dentry->d_inode;
-
- if ( !S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode) ) {
- printk(KERN_ERR
- "cowloop - %s not regular file or blockdev\n", rdof);
- return -EINVAL;
- }
-
- DEBUGP(DCOW"cowloop - determine size rdo....\n");
-
- /*
- ** determine block-size and total size of read-only file
- */
- if (S_ISREG(inode->i_mode)) {
- /*
- ** read-only file is a regular file
- */
- cowdev->blocksz = 512; /* other value fails */
- cowdev->numblocks = inode->i_size >> MUSHIFT;
-
- if (inode->i_size & MUMASK) {
- printk(KERN_WARNING
- "cowloop - rdofile %s truncated to multiple "
- "of %d bytes\n", rdof, MAPUNIT);
- }
-
- DEBUGP(DCOW"cowloop - RO=regular: numblocks=%d, blocksz=%d\n",
- cowdev->numblocks, cowdev->blocksz);
- } else {
- /*
- ** read-only file is a block device
- */
- cowdev->belowdev = inode->i_bdev;
- cowdev->belowgd = cowdev->belowdev->bd_disk; /* gendisk */
-
- if (cowdev->belowdev->bd_part) {
- cowdev->numblocks = cowdev->belowdev->bd_part->nr_sects
- / (MAPUNIT/512);
- }
-
- if (cowdev->belowgd) {
- cowdev->belowq = cowdev->belowgd->queue;
-
- if (cowdev->numblocks == 0) {
- cowdev->numblocks = get_capacity(cowdev->belowgd)
- / (MAPUNIT/512);
- }
- }
-
-
- if (cowdev->belowq)
- cowdev->blocksz = queue_logical_block_size(cowdev->belowq);
-
- if (cowdev->blocksz == 0)
- cowdev->blocksz = BLOCK_SIZE; /* default 2^10 */
-
- DEBUGP(DCOW"cowloop - numblocks=%d, "
- "blocksz=%d, belowgd=%p, belowq=%p\n",
- cowdev->numblocks, cowdev->blocksz,
- cowdev->belowgd, cowdev->belowq);
-
- DEBUGP(DCOW"cowloop - belowdev.bd_block_size=%d\n",
- cowdev->belowdev->bd_block_size);
- }
-
- if (cowdev->numblocks == 0) {
- printk(KERN_ERR "cowloop - %s has no contents\n", rdof);
- return -EINVAL;
- }
-
- /*
- ** reserve space in memory as generic I/O buffer
- */
- cowdev->iobuf = kmalloc(MAPUNIT, GFP_KERNEL);
-
- if (!cowdev->iobuf) {
- printk(KERN_ERR
- "cowloop - cannot get space for buffer %d\n", MAPUNIT);
- return -ENOMEM;
- }
-
- DEBUGP(DCOW"cowloop - determine fingerprint rdo....\n");
-
- /*
- ** determine fingerprint for read-only file
- ** calculate fingerprint from first four datablocks
- ** which do not contain binary zeroes
- */
- for (i=0, cowdev->fingerprint=0, nrval=0;
- (nrval < 4)&&(i < cowdev->numblocks); i++) {
- int j;
- unsigned char cs;
-
- /*
- ** read next block
- */
- if (cowlo_readrdo(cowdev, cowdev->iobuf, MAPUNIT,
- (loff_t)i << MUSHIFT) < 1)
- break;
-
- /*
- ** calculate fingerprint by adding all byte-values
- */
- for (j=0, cs=0; j < MAPUNIT; j++)
- cs += *(cowdev->iobuf+j);
-
- if (cs == 0) /* block probably contained zeroes */
- continue;
-
- /*
- ** shift byte-value to proper place in final fingerprint
- */
- cowdev->fingerprint |= cs << (nrval*8);
- nrval++;
- }
-
- return 0;
-}
-
-/*
-** undo memory allocs and file opens issued so far
-** related to the read-only file
-*/
-static void
-cowlo_undo_openrdo(struct cowloop_device *cowdev)
-{
- if(cowdev->iobuf);
- kfree(cowdev->iobuf);
-
- if (cowdev->rdofp)
- filp_close(cowdev->rdofp, 0);
-}
-
-/*
-** open the cowfile
-**
-** returns:
-** 0 - okay
-** < 0 - error value
-*/
-static int
-cowlo_opencow(struct cowloop_device *cowdev, char *cowf, int autorecover)
-{
- long int i, rv;
- int minor;
- unsigned long nb;
- struct file *f;
- struct inode *inode;
- loff_t offset;
- struct cowloop_device *cowtmp;
-
- DEBUGP(DCOW"cowloop - opencow called\n");
-
- /*
- ** open copy-on-write file (read-write)
- */
- if (cowf[0] == '\0') {
- printk(KERN_ERR
- "cowloop - specify name of copy-on-write file\n\n");
- return -EINVAL;
- }
-
- f = filp_open(cowf, O_RDWR|O_LARGEFILE, 0600);
-
- if ( (f == NULL) || IS_ERR(f) ) {
- /*
- ** non-existing cowfile: try to create
- */
- f = filp_open(cowf, O_RDWR|O_CREAT|O_LARGEFILE, 0600);
-
- if ( (f == NULL) || IS_ERR(f) ) {
- printk(KERN_ERR
- "cowloop - failed to open file %s for read-write\n\n",
- cowf);
- return -EINVAL;
- }
- }
-
- cowdev->cowfp = f;
-
- inode = f->f_dentry->d_inode;
-
- if (!S_ISREG(inode->i_mode)) {
- printk(KERN_ERR "cowloop - %s is not regular file\n", cowf);
- return -EINVAL;
- }
-
- /*
- ** check if this cowfile is already in use for another cowdevice
- */
- for (minor = 0; minor < maxcows; minor++) {
-
- cowtmp = cowdevall[minor];
-
- if ( !(cowtmp->state & COWDEVOPEN) )
- continue;
-
- if (cowtmp == cowdev)
- continue;
-
- if (cowtmp->cowfp->f_dentry->d_inode == f->f_dentry->d_inode) {
- printk(KERN_ERR
- "cowloop - %s: already in use as cow\n", cowf);
- return -EBUSY;
- }
- }
-
- /*
- ** mark cowfile open for read-write
- */
- cowdev->state |= COWRWCOWOPEN;
-
- /*
- ** calculate size (in bytes) for total bitmap in cowfile;
- ** when the size of the cowhead block is added, the start-offset
- ** for the modified data blocks can be found
- */
- nb = cowdev->numblocks;
-
- if (nb%8) /* transform #bits to #bytes */
- nb+=8; /* rounded if necessary */
- nb /= 8;
-
- if (nb & MUMASK) /* round up #bytes to MAPUNIT chunks */
- cowdev->mapsize = ( (nb>>MUSHIFT) +1) << MUSHIFT;
- else
- cowdev->mapsize = nb;
-
- /*
- ** reserve space in memory for the cowhead
- */
- cowdev->cowhead = kmalloc(MAPUNIT, GFP_KERNEL);
-
- if (!cowdev->cowhead) {
- printk(KERN_ERR "cowloop - cannot get space for cowhead %d\n",
- MAPUNIT);
- return -ENOMEM;
- }
-
- memset(cowdev->cowhead, 0, MAPUNIT);
-
- DEBUGP(DCOW"cowloop - prepare cowhead....\n");
-
- /*
- ** check if the cowfile exists or should be created
- */
- if (inode->i_size != 0) {
- /*
- ** existing cowfile: read the cow head
- */
- if (inode->i_size < MAPUNIT) {
- printk(KERN_ERR
- "cowloop - existing cowfile %s too small\n",
- cowf);
- return -EINVAL;
- }
-
- cowlo_readcowraw(cowdev, cowdev->cowhead, MAPUNIT, (loff_t) 0);
-
- /*
- ** verify if the existing file is really a cowfile
- */
- if (cowdev->cowhead->magic != COWMAGIC) {
- printk(KERN_ERR
- "cowloop - cowfile %s has incorrect format\n",
- cowf);
- return -EINVAL;
- }
-
- /*
- ** verify the cowhead version of the cowfile
- */
- if (cowdev->cowhead->version > COWVERSION) {
- printk(KERN_ERR
- "cowloop - cowfile %s newer than this driver\n",
- cowf);
- return -EINVAL;
- }
-
- /*
- ** make sure that this is not a packed cowfile
- */
- if (cowdev->cowhead->flags & COWPACKED) {
- printk(KERN_ERR
- "cowloop - packed cowfile %s not accepted\n", cowf);
- return -EINVAL;
- }
-
- /*
- ** verify if the cowfile has been properly closed
- */
- if (cowdev->cowhead->flags & COWDIRTY) {
- /*
- ** cowfile was not properly closed;
- ** check if automatic recovery is required
- ** (actual recovery will be done later on)
- */
- if (!autorecover) {
- printk(KERN_ERR
- "cowloop - cowfile %s is dirty "
- "(not properly closed by rmmod?)\n",
- cowf);
- printk(KERN_ERR
- "cowloop - run cowrepair or specify "
- "'option=r' to recover\n");
- return -EINVAL;
- }
- }
-
- /*
- ** verify if the cowfile is really related to this rdofile
- */
- if (cowdev->cowhead->rdoblocks != cowdev->numblocks) {
- printk(KERN_ERR
- "cowloop - cowfile %s (size %lld) not related "
- "to rdofile (size %lld)\n",
- cowf,
- (long long)cowdev->cowhead->rdoblocks <<MUSHIFT,
- (long long)cowdev->numblocks <<MUSHIFT);
- return -EINVAL;
- }
-
- if (cowdev->cowhead->rdofingerprint != cowdev->fingerprint) {
- printk(KERN_ERR
- "cowloop - cowfile %s not related to rdofile "
- " (fingerprint err - rdofile modified?)\n", cowf);
- return -EINVAL;
- }
- } else {
- /*
- ** new cowfile: determine the minimal size (cowhead+bitmap)
- */
- offset = (loff_t) MAPUNIT + cowdev->mapsize - 1;
-
- if ( cowlo_writecowraw(cowdev, "", 1, offset) < 1) {
- printk(KERN_ERR
- "cowloop - cannot set cowfile to size %lld\n",
- offset+1);
- return -EINVAL;
- }
-
- /*
- ** prepare new cowhead
- */
- cowdev->cowhead->magic = COWMAGIC;
- cowdev->cowhead->version = COWVERSION;
- cowdev->cowhead->mapunit = MAPUNIT;
- cowdev->cowhead->mapsize = cowdev->mapsize;
- cowdev->cowhead->rdoblocks = cowdev->numblocks;
- cowdev->cowhead->rdofingerprint = cowdev->fingerprint;
- cowdev->cowhead->cowused = 0;
-
- /*
- ** calculate start offset of data in cowfile,
- ** rounded up to multiple of 4K to avoid
- ** unnecessary disk-usage for written datablocks in
- ** the sparsed cowfile on e.g. 4K filesystems
- */
- cowdev->cowhead->doffset =
- ((MAPUNIT+cowdev->mapsize+4095)>>12)<<12;
- }
-
- cowdev->cowhead->flags = 0;
-
- DEBUGP(DCOW"cowloop - reserve space bitmap....\n");
-
- /*
- ** reserve space in memory for the entire bitmap and
- ** fill it with the bitmap-data from disk; the entire
- ** bitmap is allocated in several chunks because kmalloc
- ** has restrictions regarding the allowed size per kmalloc
- */
- cowdev->mapcount = (cowdev->mapsize+MAPCHUNKSZ-1)/MAPCHUNKSZ;
-
- /*
- ** the size of every bitmap chunk will be MAPCHUNKSZ bytes, except for
- ** the last bitmap chunk: calculate remaining size for this chunk
- */
- if (cowdev->mapsize % MAPCHUNKSZ == 0)
- cowdev->mapremain = MAPCHUNKSZ;
- else
- cowdev->mapremain = cowdev->mapsize % MAPCHUNKSZ;
-
- /*
- ** allocate space to store all pointers for the bitmap-chunks
- ** (initialize area with zeroes to allow proper undo)
- */
- cowdev->mapcache = kmalloc(cowdev->mapcount * sizeof(char *),
- GFP_KERNEL);
- if (!cowdev->mapcache) {
- printk(KERN_ERR
- "cowloop - can not allocate space for bitmap ptrs\n");
- return -ENOMEM;
- }
-
- memset(cowdev->mapcache, 0, cowdev->mapcount * sizeof(char *));
-
- /*
- ** allocate space to store the bitmap-chunks themselves
- */
- for (i=0; i < cowdev->mapcount; i++) {
- if (i < (cowdev->mapcount-1))
- *(cowdev->mapcache+i) = kmalloc(MAPCHUNKSZ, GFP_KERNEL);
- else
- *(cowdev->mapcache+i) = kmalloc(cowdev->mapremain,
- GFP_KERNEL);
-
- if (*(cowdev->mapcache+i) == NULL) {
- printk(KERN_ERR "cowloop - no space for bitmapchunk %ld"
- " totmapsz=%ld, mapcnt=%d mapunit=%d\n",
- i, cowdev->mapsize, cowdev->mapcount,
- MAPUNIT);
- return -ENOMEM;
- }
- }
-
- DEBUGP(DCOW"cowloop - read bitmap from cow....\n");
-
- /*
- ** read the entire bitmap from the cowfile into the in-memory cache;
- ** count the number of blocks that are in use already
- ** (statistical purposes)
- */
- for (i=0, offset=MAPUNIT; i < cowdev->mapcount;
- i++, offset+=MAPCHUNKSZ) {
- unsigned long numbytes;
-
- if (i < (cowdev->mapcount-1))
- /*
- ** full bitmap chunk
- */
- numbytes = MAPCHUNKSZ;
- else
- /*
- ** last bitmap chunk: might be partly filled
- */
- numbytes = cowdev->mapremain;
-
- cowlo_readcowraw(cowdev, *(cowdev->mapcache+i),
- numbytes, offset);
- }
-
- /*
- ** if the cowfile was dirty and automatic recovery is required,
- ** reconstruct a proper bitmap in memory now
- */
- if (cowdev->cowhead->flags & COWDIRTY) {
- unsigned long long blocknum;
- char databuf[MAPUNIT];
- unsigned long mapnum, mapbyte, mapbit;
-
- printk(KERN_NOTICE "cowloop - recover dirty cowfile %s....\n",
- cowf);
-
- /*
- ** read all data blocks
- */
- for (blocknum=0, rv=1, offset=0;
- cowlo_readcow(cowdev, databuf, MAPUNIT, offset) > 0;
- blocknum++, offset += MAPUNIT) {
-
- /*
- ** if this datablock contains real data (not binary
- ** zeroes), set the corresponding bit in the bitmap
- */
- if ( memcmp(databuf, allzeroes, MAPUNIT) == 0)
- continue;
-
- mapnum = CALCMAP (blocknum);
- mapbyte = CALCBYTE(blocknum);
- mapbit = CALCBIT (blocknum);
-
- *(*(cowdev->mapcache+mapnum)+mapbyte) |= (1<<mapbit);
- }
-
- printk(KERN_NOTICE "cowloop - cowfile recovery completed\n");
- }
-
- /*
- ** count all bits set in the bitmaps for statistical purposes
- */
- for (i=0, cowdev->nrcowblocks = 0; i < cowdev->mapcount; i++) {
- long numbytes;
- char *p;
-
- if (i < (cowdev->mapcount-1))
- numbytes = MAPCHUNKSZ;
- else
- numbytes = cowdev->mapremain;
-
- p = *(cowdev->mapcache+i);
-
- for (numbytes--; numbytes >= 0; numbytes--, p++) {
- /*
- ** for only eight checks the following construction
- ** is faster than a loop-construction
- */
- if ((*p) & 0x01) cowdev->nrcowblocks++;
- if ((*p) & 0x02) cowdev->nrcowblocks++;
- if ((*p) & 0x04) cowdev->nrcowblocks++;
- if ((*p) & 0x08) cowdev->nrcowblocks++;
- if ((*p) & 0x10) cowdev->nrcowblocks++;
- if ((*p) & 0x20) cowdev->nrcowblocks++;
- if ((*p) & 0x40) cowdev->nrcowblocks++;
- if ((*p) & 0x80) cowdev->nrcowblocks++;
- }
- }
-
- /*
- ** consistency-check for number of bits set in bitmap
- */
- if ( !(cowdev->cowhead->flags & COWDIRTY) &&
- (cowdev->cowhead->cowused != cowdev->nrcowblocks) ) {
- printk(KERN_ERR "cowloop - inconsistent cowfile admi\n");
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
-** undo memory allocs and file opens issued so far
-** related to the cowfile
-*/
-static void
-cowlo_undo_opencow(struct cowloop_device *cowdev)
-{
- int i;
-
- if (cowdev->mapcache) {
- for (i=0; i < cowdev->mapcount; i++) {
- if (*(cowdev->mapcache+i) != NULL)
- kfree( *(cowdev->mapcache+i) );
- }
-
- kfree(cowdev->mapcache);
- }
-
- if (cowdev->cowhead)
- kfree(cowdev->cowhead);
-
- if ( (cowdev->state & COWCOWOPEN) && (cowdev->cowfp) )
- filp_close(cowdev->cowfp, 0);
-
- /*
- ** mark cowfile closed
- */
- cowdev->state &= ~COWCOWOPEN;
-}
-
-/*
-** flush the entire bitmap and the cowhead (clean) to the cowfile
-**
-** must be called with the cowdevices-lock set
-*/
-static void
-cowlo_sync(void)
-{
- int i, minor;
- loff_t offset;
- struct cowloop_device *cowdev;
-
- for (minor=0; minor < maxcows; minor++) {
- cowdev = cowdevall[minor];
- if ( ! (cowdev->state & COWRWCOWOPEN) )
- continue;
-
- for (i=0, offset=MAPUNIT; i < cowdev->mapcount;
- i++, offset += MAPCHUNKSZ) {
- unsigned long numbytes;
-
- if (i < (cowdev->mapcount-1))
- /*
- ** full bitmap chunk
- */
- numbytes = MAPCHUNKSZ;
- else
- /*
- ** last bitmap chunk: might be partly filled
- */
- numbytes = cowdev->mapremain;
-
- DEBUGP(DCOW
- "cowloop - flushing bitmap %2d (%3ld Kb)\n",
- i, numbytes/1024);
-
- if (cowlo_writecowraw(cowdev, *(cowdev->mapcache+i),
- numbytes, offset) < numbytes) {
- break;
- }
- }
-
- /*
- ** flush clean up-to-date cowhead to cowfile
- */
- cowdev->cowhead->cowused = cowdev->nrcowblocks;
- cowdev->cowhead->flags &= ~COWDIRTY;
-
- DEBUGP(DCOW "cowloop - flushing cowhead (%3d Kb)\n",
- MAPUNIT/1024);
-
- cowlo_writecowraw(cowdev, cowdev->cowhead, MAPUNIT, (loff_t) 0);
- }
-}
-
-/*****************************************************************************/
-/* Module loading/unloading */
-/*****************************************************************************/
-
-/*
-** called during insmod/modprobe
-*/
-static int __init
-cowlo_init_module(void)
-{
- int rv;
- int minor, uptocows;
-
- revision[sizeof revision - 3] = '\0';
-
- printk(KERN_NOTICE "cowloop - (C) 2009 ATComputing.nl - version: %s\n", &revision[11]);
- printk(KERN_NOTICE "cowloop - info: www.ATComputing.nl/cowloop\n");
-
- memset(allzeroes, 0, MAPUNIT);
-
- /*
- ** Setup administration for all possible cowdevices.
- ** Note that their minor numbers go from 0 to MAXCOWS-1 inclusive
- ** and minor == MAXCOWS-1 is reserved for the control device.
- */
- if ((maxcows < 1) || (maxcows > MAXCOWS)) {
- printk(KERN_WARNING
- "cowloop - maxcows exceeds maximum of %d\n", MAXCOWS);
-
- maxcows = DFLCOWS;
- }
-
- /* allocate room for a table with a pointer to each cowloop_device: */
- if ( (cowdevall = kmalloc(maxcows * sizeof(struct cowloop_device *),
- GFP_KERNEL)) == NULL) {
- printk(KERN_WARNING
- "cowloop - can not alloc table for %d devs\n", maxcows);
- uptocows = 0;
- rv = -ENOMEM;
- goto error_out;
- }
- memset(cowdevall, 0, maxcows * sizeof(struct cowloop_device *));
- /* then hook an actual cowloop_device struct to each pointer: */
- for (minor=0; minor < maxcows; minor++) {
- if ((cowdevall[minor] = kmalloc(sizeof(struct cowloop_device),
- GFP_KERNEL)) == NULL) {
- printk(KERN_WARNING
- "cowloop - can not alloc admin-struct for dev no %d\n", minor);
-
- uptocows = minor; /* this is how far we got.... */
- rv = -ENOMEM;
- goto error_out;
- }
- memset(cowdevall[minor], 0, sizeof(struct cowloop_device));
- }
- uptocows = maxcows; /* we got all devices */
-
- sema_init(&cowdevlock, 1);
-
- /*
- ** register cowloop module
- */
- if ( register_blkdev(COWMAJOR, DEVICE_NAME) < 0) {
- printk(KERN_WARNING
- "cowloop - unable to get major %d for cowloop\n", COWMAJOR);
- rv = -EIO;
- goto error_out;
- }
-
- /*
- ** create a directory below /proc to allocate a file
- ** for each cowdevice that is allocated later on
- */
- cowlo_procdir = proc_mkdir("cow", NULL);
-
- /*
- ** check if a cowdevice has to be opened during insmod/modprobe;
- ** two parameters should be specified then: rdofile= and cowfile=
- */
- if( (rdofile[0] != '\0') && (cowfile[0] != '\0') ) {
- char *po = option;
- int wantrecover = 0;
-
- /*
- ** check if automatic recovery is wanted
- */
- while (*po) {
- if (*po == 'r') {
- wantrecover = 1;
- break;
- }
- po++;
- }
-
- /*
- ** open new cowdevice with minor number 0
- */
- if ( (rv = cowlo_openpair(rdofile, cowfile, wantrecover, 0))) {
- remove_proc_entry("cow", NULL);
- unregister_blkdev(COWMAJOR, DEVICE_NAME);
- goto error_out;
- }
- } else {
- /*
- ** check if only one parameter has been specified
- */
- if( (rdofile[0] != '\0') || (cowfile[0] != '\0') ) {
- printk(KERN_ERR
- "cowloop - only one filename specified\n");
- remove_proc_entry("cow", NULL);
- unregister_blkdev(COWMAJOR, DEVICE_NAME);
- rv = -EINVAL;
- goto error_out;
- }
- }
-
- /*
- ** allocate fake disk as control channel to handle the requests
- ** to activate and deactivate cowdevices dynamically
- */
- if (!(cowctlgd = alloc_disk(1))) {
- printk(KERN_WARNING
- "cowloop - unable to alloc_disk for cowctl\n");
-
- remove_proc_entry("cow", NULL);
- (void) cowlo_closepair(cowdevall[0]);
- unregister_blkdev(COWMAJOR, DEVICE_NAME);
- rv = -ENOMEM;
- goto error_out;
- }
-
- spin_lock_init(&cowctlrqlock);
- cowctlgd->major = COWMAJOR;
- cowctlgd->first_minor = COWCTL;
- cowctlgd->minors = 1;
- cowctlgd->fops = &cowlo_fops;
- cowctlgd->private_data = NULL;
- /* the device has capacity 0, so there will be no q-requests */
- cowctlgd->queue = blk_init_queue(NULL, &cowctlrqlock);
- sprintf(cowctlgd->disk_name, "cowctl");
- set_capacity(cowctlgd, 0);
-
- add_disk(cowctlgd);
-
- printk(KERN_NOTICE "cowloop - number of configured cowdevices: %d\n",
- maxcows);
- if (rdofile[0] != '\0') {
- printk(KERN_NOTICE "cowloop - initialized on rdofile=%s\n",
- rdofile);
- } else {
- printk(KERN_NOTICE "cowloop - initialized without rdofile yet\n");
- }
- return 0;
-
-error_out:
- for (minor=0; minor < uptocows ; minor++) {
- kfree(cowdevall[minor]);
- }
- kfree(cowdevall);
- return rv;
-}
-
-/*
-** called during rmmod
-*/
-static void __exit
-cowlo_cleanup_module(void)
-{
- int minor;
-
- /*
- ** flush bitmaps and cowheads to the cowfiles
- */
- down(&cowdevlock);
- cowlo_sync();
- up(&cowdevlock);
-
- /*
- ** close all cowdevices
- */
- for (minor=0; minor < maxcows; minor++)
- (void) cowlo_closepair(cowdevall[minor]);
-
- unregister_blkdev(COWMAJOR, DEVICE_NAME);
-
- /*
- ** get rid of /proc/cow and unregister the driver
- */
- remove_proc_entry("cow", NULL);
-
- for (minor = 0; minor < maxcows; minor++) {
- kfree(cowdevall[minor]);
- }
- kfree(cowdevall);
-
- del_gendisk(cowctlgd); /* revert the alloc_disk() */
- put_disk (cowctlgd); /* revert the add_disk() */
- blk_cleanup_queue(cowctlgd->queue); /* cleanup the empty queue */
-
- printk(KERN_NOTICE "cowloop - unloaded\n");
-}
-
-module_init(cowlo_init_module);
-module_exit(cowlo_cleanup_module);
diff --git a/drivers/staging/cowloop/cowloop.h b/drivers/staging/cowloop/cowloop.h
deleted file mode 100644
index bbd4a35ac667..000000000000
--- a/drivers/staging/cowloop/cowloop.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-** DO NOT MODIFY THESE VALUES (would make old cowfiles unusable)
-*/
-#define MAPUNIT 1024 /* blocksize for bit in bitmap */
-#define MUSHIFT 10 /* bitshift for bit in bitmap */
-#define MUMASK 0x3ff /* bitmask for bit in bitmap */
-
-#define COWMAGIC 0x574f437f /* byte-swapped '7f C O W' */
-#define COWDIRTY 0x01
-#define COWPACKED 0x02
-#define COWVERSION 1
-
-struct cowhead
-{
- int magic; /* identifies a cowfile */
- short version; /* version of cowhead */
- short flags; /* flags indicating status */
- unsigned long mapunit; /* blocksize per bit in bitmap */
- unsigned long mapsize; /* total size of bitmap (bytes) */
- unsigned long doffset; /* start-offset datablocks in cow */
- unsigned long rdoblocks; /* size of related read-only file */
- unsigned long rdofingerprint; /* fingerprint of read-only file */
- unsigned long cowused; /* number of datablocks used in cow */
-};
-
-#define COWDEVDIR "/dev/cow/"
-#define COWDEVICE COWDEVDIR "%ld"
-#define COWCONTROL COWDEVDIR "ctl"
-
-#define MAXCOWS 1024
-#define COWCTL (MAXCOWS-1) /* minor number of /dev/cow/ctl */
-
-#define COWPROCDIR "/proc/cow/"
-#define COWPROCFILE COWPROCDIR "%d"
-
-/*
-** ioctl related stuff
-*/
-#define ANYDEV ((unsigned long)-1)
-
-struct cowpair
-{
- unsigned char *rdofile; /* pathname of the rdofile */
- unsigned char *cowfile; /* pathname of the cowfile */
- unsigned short rdoflen; /* length of rdofile pathname */
- unsigned short cowflen; /* length of cowfile pathname */
- unsigned long device; /* requested/returned device number */
-};
-
-struct cowwatch
-{
- int flags; /* request flags */
- unsigned long device; /* requested device number */
- unsigned long threshold; /* continue if free Kb < threshold */
- unsigned long totalkb; /* ret: total filesystem size (Kb) */
- unsigned long availkb; /* ret: free filesystem size (Kb) */
-};
-
-#define WATCHWAIT 0x01 /* block until threshold reached */
-
-#define COWSYNC _IO ('C', 1)
-#define COWMKPAIR _IOW ('C', 2, struct cowpair)
-#define COWRMPAIR _IOW ('C', 3, unsigned long)
-#define COWWATCH _IOW ('C', 4, struct cowwatch)
-#define COWCLOSE _IOW ('C', 5, unsigned long)
-#define COWRDOPEN _IOW ('C', 6, unsigned long)
diff --git a/drivers/staging/et131x/et1310_address_map.h b/drivers/staging/et131x/et1310_address_map.h
index 6294d3814e72..2c3d65a622a7 100644
--- a/drivers/staging/et131x/et1310_address_map.h
+++ b/drivers/staging/et131x/et1310_address_map.h
@@ -223,7 +223,7 @@ typedef union _TXDMA_PR_NUM_DES_t {
extern inline void add_10bit(u32 *v, int n)
{
- *v = INDEX10(*v + n);
+ *v = INDEX10(*v + n) | (*v & ET_DMA10_WRAP);
}
/*
diff --git a/drivers/staging/et131x/et1310_rx.c b/drivers/staging/et131x/et1310_rx.c
index 8f2e91fa0a86..10e21db57ac3 100644
--- a/drivers/staging/et131x/et1310_rx.c
+++ b/drivers/staging/et131x/et1310_rx.c
@@ -1177,12 +1177,20 @@ void et131x_handle_recv_interrupt(struct et131x_adapter *etdev)
static inline u32 bump_fbr(u32 *fbr, u32 limit)
{
- u32 v = *fbr;
- add_10bit(&v, 1);
- if (v > limit)
- v = (*fbr & ~ET_DMA10_MASK) ^ ET_DMA10_WRAP;
- *fbr = v;
- return v;
+ u32 v = *fbr;
+ v++;
+ /* This works for all cases where limit < 1024. The 1023 case
+ works because 1023++ is 1024 which means the if condition is not
+ taken but the carry of the bit into the wrap bit toggles the wrap
+ value correctly */
+ if ((v & ET_DMA10_MASK) > limit) {
+ v &= ~ET_DMA10_MASK;
+ v ^= ET_DMA10_WRAP;
+ }
+ /* For the 1023 case */
+ v &= (ET_DMA10_MASK|ET_DMA10_WRAP);
+ *fbr = v;
+ return v;
}
/**
diff --git a/drivers/staging/hv/osd.c b/drivers/staging/hv/osd.c
index 8fe543bd9910..3a4793a0fd05 100644
--- a/drivers/staging/hv/osd.c
+++ b/drivers/staging/hv/osd.c
@@ -30,6 +30,7 @@
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index beb99a547f09..4586650d65c3 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -4,6 +4,7 @@
menuconfig IIO
tristate "Industrial I/O support"
+ depends on !S390
---help---
The industrial I/O subsystem provides a unified framework for
drivers for many different types of embedded sensors using a
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c
index 1fa18f255814..768f44894d08 100644
--- a/drivers/staging/iio/industrialio-core.c
+++ b/drivers/staging/iio/industrialio-core.c
@@ -18,6 +18,8 @@
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
#include <linux/cdev.h>
#include "iio.h"
#include "trigger_consumer.h"
diff --git a/drivers/staging/p9auth/p9auth.c b/drivers/staging/p9auth/p9auth.c
index 9111dcba37a1..8ccfff723eec 100644
--- a/drivers/staging/p9auth/p9auth.c
+++ b/drivers/staging/p9auth/p9auth.c
@@ -183,7 +183,7 @@ static ssize_t cap_write(struct file *filp, const char __user *buf,
user_buf_running = NULL;
hash_str = NULL;
node_ptr = kmalloc(sizeof(struct cap_node), GFP_KERNEL);
- user_buf = kzalloc(count, GFP_KERNEL);
+ user_buf = kzalloc(count+1, GFP_KERNEL);
if (!node_ptr || !user_buf)
goto out;
@@ -207,6 +207,7 @@ static ssize_t cap_write(struct file *filp, const char __user *buf,
list_add(&(node_ptr->list), &(dev->head->list));
node_ptr = NULL;
} else {
+ char *tmpu;
if (!cap_devices[0].head ||
list_empty(&(cap_devices[0].head->list))) {
retval = -EINVAL;
@@ -218,10 +219,10 @@ static ssize_t cap_write(struct file *filp, const char __user *buf,
* need to split it and hash 'user1@user2' using 'randomstring'
* as the key.
*/
- user_buf_running = kstrdup(user_buf, GFP_KERNEL);
- source_user = strsep(&user_buf_running, "@");
- target_user = strsep(&user_buf_running, "@");
- rand_str = strsep(&user_buf_running, "@");
+ tmpu = user_buf_running = kstrdup(user_buf, GFP_KERNEL);
+ source_user = strsep(&tmpu, "@");
+ target_user = strsep(&tmpu, "@");
+ rand_str = tmpu;
if (!source_user || !target_user || !rand_str) {
retval = -EINVAL;
goto out;
@@ -229,7 +230,8 @@ static ssize_t cap_write(struct file *filp, const char __user *buf,
/* hash the string user1@user2 with rand_str as the key */
len = strlen(source_user) + strlen(target_user) + 1;
- hash_str = kzalloc(len, GFP_KERNEL);
+ /* src, @, len, \0 */
+ hash_str = kzalloc(len+1, GFP_KERNEL);
strcat(hash_str, source_user);
strcat(hash_str, "@");
strcat(hash_str, target_user);
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index dd7d3fde9699..51e94a13f99f 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/poch/poch.c b/drivers/staging/poch/poch.c
index 0d111ddfabb2..2eb8e3d43c4d 100644
--- a/drivers/staging/poch/poch.c
+++ b/drivers/staging/poch/poch.c
@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/ioctl.h>
#include <linux/io.h>
+#include <linux/sched.h>
#include "poch.h"
diff --git a/drivers/staging/rt2860/common/cmm_data_2860.c b/drivers/staging/rt2860/common/cmm_data_2860.c
index fb1735533b74..857ff450b6c9 100644
--- a/drivers/staging/rt2860/common/cmm_data_2860.c
+++ b/drivers/staging/rt2860/common/cmm_data_2860.c
@@ -363,6 +363,8 @@ int RtmpPCIMgmtKickOut(
ULONG SwIdx = pAd->MgmtRing.TxCpuIdx;
pTxD = (PTXD_STRUC) pAd->MgmtRing.Cell[SwIdx].AllocVa;
+ if (!pTxD)
+ return 0;
pAd->MgmtRing.Cell[SwIdx].pNdisPacket = pPacket;
pAd->MgmtRing.Cell[SwIdx].pNextNdisPacket = NULL;
diff --git a/drivers/staging/rt2860/common/cmm_info.c b/drivers/staging/rt2860/common/cmm_info.c
index 9d589c240ed0..019cc4474ce8 100644
--- a/drivers/staging/rt2860/common/cmm_info.c
+++ b/drivers/staging/rt2860/common/cmm_info.c
@@ -25,6 +25,7 @@
*************************************************************************
*/
+#include <linux/sched.h>
#include "../rt_config.h"
INT Show_SSID_Proc(
diff --git a/drivers/staging/rt2860/rt_linux.c b/drivers/staging/rt2860/rt_linux.c
index b396a9b570e2..ed27b8545a1b 100644
--- a/drivers/staging/rt2860/rt_linux.c
+++ b/drivers/staging/rt2860/rt_linux.c
@@ -25,6 +25,7 @@
*************************************************************************
*/
+#include <linux/sched.h>
#include "rt_config.h"
ULONG RTDebugLevel = RT_DEBUG_ERROR;
diff --git a/drivers/staging/rt3090/common/cmm_info.c b/drivers/staging/rt3090/common/cmm_info.c
index 5be0714666cb..3e51e98b474c 100644
--- a/drivers/staging/rt3090/common/cmm_info.c
+++ b/drivers/staging/rt3090/common/cmm_info.c
@@ -34,6 +34,7 @@
--------- ---------- ----------------------------------------------
*/
+#include <linux/sched.h>
#include "../rt_config.h"
diff --git a/drivers/staging/rt3090/rt_linux.c b/drivers/staging/rt3090/rt_linux.c
index d2241ecdf583..9b94aa6eb904 100644
--- a/drivers/staging/rt3090/rt_linux.c
+++ b/drivers/staging/rt3090/rt_linux.c
@@ -25,6 +25,7 @@
*************************************************************************
*/
+#include <linux/sched.h>
#include "rt_config.h"
ULONG RTDebugLevel = RT_DEBUG_ERROR;
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/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/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c
index d4fa65489655..b0802a7aeb5f 100644
--- a/drivers/staging/rtl8192e/r8192E_core.c
+++ b/drivers/staging/rtl8192e/r8192E_core.c
@@ -46,6 +46,7 @@
#undef DEBUG_TX_DESC
//#define CONFIG_RTL8192_IO_MAP
+#include <linux/vmalloc.h>
#include <asm/uaccess.h>
#include "r8192E_hw.h"
#include "r8192E.h"
diff --git a/drivers/staging/sep/sep_driver.c b/drivers/staging/sep/sep_driver.c
index 87f8a1192762..f890a16096c0 100644
--- a/drivers/staging/sep/sep_driver.c
+++ b/drivers/staging/sep/sep_driver.c
@@ -38,6 +38,7 @@
#include <linux/mm.h>
#include <linux/poll.h>
#include <linux/wait.h>
+#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/firmware.h>
#include <asm/ioctl.h>
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/vme/bridges/vme_ca91cx42.c b/drivers/staging/vme/bridges/vme_ca91cx42.c
index 3d2a84c45829..e139eaeaa174 100644
--- a/drivers/staging/vme/bridges/vme_ca91cx42.c
+++ b/drivers/staging/vme/bridges/vme_ca91cx42.c
@@ -25,6 +25,7 @@
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/sched.h>
#include <asm/time.h>
#include <asm/io.h>
#include <asm/uaccess.h>
diff --git a/drivers/staging/vme/bridges/vme_tsi148.c b/drivers/staging/vme/bridges/vme_tsi148.c
index 8960fa9ee7aa..00fe0803c21c 100644
--- a/drivers/staging/vme/bridges/vme_tsi148.c
+++ b/drivers/staging/vme/bridges/vme_tsi148.c
@@ -25,6 +25,7 @@
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/sched.h>
#include <asm/time.h>
#include <asm/io.h>
#include <asm/uaccess.h>
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/winbond/wbusb.c b/drivers/staging/winbond/wbusb.c
index 8950724f168e..067082a7d759 100644
--- a/drivers/staging/winbond/wbusb.c
+++ b/drivers/staging/winbond/wbusb.c
@@ -51,10 +51,26 @@ static struct ieee80211_supported_band wbsoft_band_2GHz = {
.n_bitrates = ARRAY_SIZE(wbsoft_rates),
};
+static void hal_set_beacon_period(struct hw_data *pHwData, u16 beacon_period)
+{
+ u32 tmp;
+
+ if (pHwData->SurpriseRemove)
+ return;
+
+ pHwData->BeaconPeriod = beacon_period;
+ tmp = pHwData->BeaconPeriod << 16;
+ tmp |= pHwData->ProbeDelay;
+ Wb35Reg_Write(pHwData, 0x0848, tmp);
+}
+
static int wbsoft_add_interface(struct ieee80211_hw *dev,
struct ieee80211_if_init_conf *conf)
{
- printk("wbsoft_add interface called\n");
+ struct wbsoft_priv *priv = dev->priv;
+
+ hal_set_beacon_period(&priv->sHwData, conf->vif->bss_conf.beacon_int);
+
return 0;
}
@@ -83,10 +99,16 @@ static int wbsoft_get_tx_stats(struct ieee80211_hw *hw,
return 0;
}
+static u64 wbsoft_prepare_multicast(struct ieee80211_hw *hw, int mc_count,
+ struct dev_addr_list *mc_list)
+{
+ return mc_count;
+}
+
static void wbsoft_configure_filter(struct ieee80211_hw *dev,
unsigned int changed_flags,
unsigned int *total_flags,
- int mc_count, struct dev_mc_list *mclist)
+ u64 multicast)
{
unsigned int new_flags;
@@ -94,7 +116,7 @@ static void wbsoft_configure_filter(struct ieee80211_hw *dev,
if (*total_flags & FIF_PROMISC_IN_BSS)
new_flags |= FIF_PROMISC_IN_BSS;
- else if ((*total_flags & FIF_ALLMULTI) || (mc_count > 32))
+ else if ((*total_flags & FIF_ALLMULTI) || (multicast > 32))
new_flags |= FIF_ALLMULTI;
dev->flags &= ~IEEE80211_HW_RX_INCLUDES_FCS;
@@ -138,19 +160,6 @@ static void hal_set_radio_mode(struct hw_data *pHwData, unsigned char radio_off)
Wb35Reg_Write(pHwData, 0x0824, reg->M24_MacControl);
}
-static void hal_set_beacon_period(struct hw_data *pHwData, u16 beacon_period)
-{
- u32 tmp;
-
- if (pHwData->SurpriseRemove)
- return;
-
- pHwData->BeaconPeriod = beacon_period;
- tmp = pHwData->BeaconPeriod << 16;
- tmp |= pHwData->ProbeDelay;
- Wb35Reg_Write(pHwData, 0x0848, tmp);
-}
-
static void
hal_set_current_channel_ex(struct hw_data *pHwData, ChanInfo channel)
{
@@ -244,7 +253,6 @@ static void hal_set_accept_beacon(struct hw_data *pHwData, u8 enable)
static int wbsoft_config(struct ieee80211_hw *dev, u32 changed)
{
struct wbsoft_priv *priv = dev->priv;
- struct ieee80211_conf *conf = &dev->conf;
ChanInfo ch;
printk("wbsoft_config called\n");
@@ -254,7 +262,6 @@ static int wbsoft_config(struct ieee80211_hw *dev, u32 changed)
ch.ChanNo = 1;
hal_set_current_channel(&priv->sHwData, ch);
- hal_set_beacon_period(&priv->sHwData, conf->beacon_int);
hal_set_accept_broadcast(&priv->sHwData, 1);
hal_set_accept_promiscuous(&priv->sHwData, 1);
hal_set_accept_multicast(&priv->sHwData, 1);
@@ -277,6 +284,7 @@ static const struct ieee80211_ops wbsoft_ops = {
.add_interface = wbsoft_add_interface,
.remove_interface = wbsoft_remove_interface,
.config = wbsoft_config,
+ .prepare_multicast = wbsoft_prepare_multicast,
.configure_filter = wbsoft_configure_filter,
.get_stats = wbsoft_get_stats,
.get_tx_stats = wbsoft_get_tx_stats,
diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c
index a9d707047202..e941367dd28f 100644
--- a/drivers/uio/uio.c
+++ b/drivers/uio/uio.c
@@ -19,6 +19,7 @@
#include <linux/device.h>
#include <linux/mm.h>
#include <linux/idr.h>
+#include <linux/sched.h>
#include <linux/string.h>
#include <linux/kobject.h>
#include <linux/uio_driver.h>
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 864f0ba6a344..2473cf0c6b1d 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -39,7 +39,7 @@
#define USBTMC_SIZE_IOBUFFER 2048
/* Default USB timeout (in milliseconds) */
-#define USBTMC_TIMEOUT 10
+#define USBTMC_TIMEOUT 5000
/*
* Maximum number of read cycles to empty bulk in endpoint during CLEAR and
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index f37de283d0ab..167cb2a8ecef 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -61,11 +61,6 @@
* simpler, Microsoft pushes their own approach: RNDIS. The published
* RNDIS specs are ambiguous and appear to be incomplete, and are also
* needlessly complex. They borrow more from CDC ACM than CDC ECM.
- *
- * While CDC ECM, CDC Subset, and RNDIS are designed to extend the ethernet
- * interface to the target, CDC EEM was designed to use ethernet over the USB
- * link between the host and target. CDC EEM is implemented as an alternative
- * to those other protocols when that communication model is more appropriate
*/
#define DRIVER_DESC "Ethernet Gadget"
@@ -157,8 +152,8 @@ static inline bool has_rndis(void)
#define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */
/* For EEM gadgets */
-#define EEM_VENDOR_NUM 0x0525 /* INVALID - NEEDS TO BE ALLOCATED */
-#define EEM_PRODUCT_NUM 0xa4a1 /* INVALID - NEEDS TO BE ALLOCATED */
+#define EEM_VENDOR_NUM 0x1d6b /* Linux Foundation */
+#define EEM_PRODUCT_NUM 0x0102 /* EEM Gadget */
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index c52a681f376c..01ee0b9bc957 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -1402,7 +1402,8 @@ static int __init imx_udc_probe(struct platform_device *pdev)
struct clk *clk;
void __iomem *base;
int ret = 0;
- int i, res_size;
+ int i;
+ resource_size_t res_size;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
@@ -1416,7 +1417,7 @@ static int __init imx_udc_probe(struct platform_device *pdev)
return -ENODEV;
}
- res_size = res->end - res->start + 1;
+ res_size = resource_size(res);
if (!request_mem_region(res->start, res_size, res->name)) {
dev_err(&pdev->dev, "can't allocate %d bytes at %d address\n",
res_size, res->start);
@@ -1527,8 +1528,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
clk_disable(imx_usb->clk);
iounmap(imx_usb->base);
- release_mem_region(imx_usb->res->start,
- imx_usb->res->end - imx_usb->res->start + 1);
+ release_mem_region(imx_usb->res->start, resource_size(imx_usb->res));
if (pdata->exit)
pdata->exit(&pdev->dev);
diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h
index 03087e7b9190..9a537aa07968 100644
--- a/drivers/usb/gadget/r8a66597-udc.h
+++ b/drivers/usb/gadget/r8a66597-udc.h
@@ -131,31 +131,48 @@ static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
}
static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
- unsigned long offset, u16 *buf,
+ unsigned long offset,
+ unsigned char *buf,
int len)
{
+ unsigned long fifoaddr = r8a66597->reg + offset;
+ unsigned int data;
+ int i;
+
if (r8a66597->pdata->on_chip) {
- unsigned long fifoaddr = r8a66597->reg + offset;
- unsigned long count;
- union {
- unsigned long dword;
- unsigned char byte[4];
- } data;
- unsigned char *pb;
- int i;
-
- count = len / 4;
- insl(fifoaddr, buf, count);
-
- if (len & 0x00000003) {
- data.dword = inl(fifoaddr);
- pb = (unsigned char *)buf + count * 4;
- for (i = 0; i < (len & 0x00000003); i++)
- pb[i] = data.byte[i];
+ /* 32-bit accesses for on_chip controllers */
+
+ /* aligned buf case */
+ if (len >= 4 && !((unsigned long)buf & 0x03)) {
+ insl(fifoaddr, buf, len / 4);
+ buf += len & ~0x03;
+ len &= 0x03;
+ }
+
+ /* unaligned buf case */
+ for (i = 0; i < len; i++) {
+ if (!(i & 0x03))
+ data = inl(fifoaddr);
+
+ buf[i] = (data >> ((i & 0x03) * 8)) & 0xff;
}
} else {
- len = (len + 1) / 2;
- insw(r8a66597->reg + offset, buf, len);
+ /* 16-bit accesses for external controllers */
+
+ /* aligned buf case */
+ if (len >= 2 && !((unsigned long)buf & 0x01)) {
+ insw(fifoaddr, buf, len / 2);
+ buf += len & ~0x01;
+ len &= 0x01;
+ }
+
+ /* unaligned buf case */
+ for (i = 0; i < len; i++) {
+ if (!(i & 0x01))
+ data = inw(fifoaddr);
+
+ buf[i] = (data >> ((i & 0x01) * 8)) & 0xff;
+ }
}
}
@@ -166,38 +183,40 @@ static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
}
static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
- unsigned long offset, u16 *buf,
+ unsigned long offset,
+ unsigned char *buf,
int len)
{
unsigned long fifoaddr = r8a66597->reg + offset;
+ int adj = 0;
+ int i;
if (r8a66597->pdata->on_chip) {
- unsigned long count;
- unsigned char *pb;
- int i;
-
- count = len / 4;
- outsl(fifoaddr, buf, count);
-
- if (len & 0x00000003) {
- pb = (unsigned char *)buf + count * 4;
- for (i = 0; i < (len & 0x00000003); i++) {
- if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
- outb(pb[i], fifoaddr + i);
- else
- outb(pb[i], fifoaddr + 3 - i);
- }
+ /* 32-bit access only if buf is 32-bit aligned */
+ if (len >= 4 && !((unsigned long)buf & 0x03)) {
+ outsl(fifoaddr, buf, len / 4);
+ buf += len & ~0x03;
+ len &= 0x03;
}
} else {
- int odd = len & 0x0001;
-
- len = len / 2;
- outsw(fifoaddr, buf, len);
- if (unlikely(odd)) {
- buf = &buf[len];
- outb((unsigned char)*buf, fifoaddr);
+ /* 16-bit access only if buf is 16-bit aligned */
+ if (len >= 2 && !((unsigned long)buf & 0x01)) {
+ outsw(fifoaddr, buf, len / 2);
+ buf += len & ~0x01;
+ len &= 0x01;
}
}
+
+ /* adjust fifo address in the little endian case */
+ if (!(r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)) {
+ if (r8a66597->pdata->on_chip)
+ adj = 0x03; /* 32-bit wide */
+ else
+ adj = 0x01; /* 16-bit wide */
+ }
+
+ for (i = 0; i < len; i++)
+ outb(buf[i], fifoaddr + adj - (i & adj));
}
static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 3ea05936851f..b25cdea93a1f 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1400,6 +1400,10 @@ iso_stream_schedule (
goto fail;
}
+ period = urb->interval;
+ if (!stream->highspeed)
+ period <<= 3;
+
now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
/* when's the last uframe this urb could start? */
@@ -1417,14 +1421,15 @@ iso_stream_schedule (
/* Fell behind (by up to twice the slop amount)? */
if (start >= max - 2 * 8 * SCHEDULE_SLOP)
- start += stream->interval * DIV_ROUND_UP(
- max - start, stream->interval) - mod;
+ start += period * DIV_ROUND_UP(
+ max - start, period) - mod;
/* Tried to schedule too far into the future? */
if (unlikely((start + sched->span) >= max)) {
status = -EFBIG;
goto fail;
}
+ stream->next_uframe = start;
goto ready;
}
@@ -1440,10 +1445,6 @@ iso_stream_schedule (
/* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
- period = urb->interval;
- if (!stream->highspeed)
- period <<= 3;
-
/* find a uframe slot with enough bandwidth */
for (; start < (stream->next_uframe + period); start++) {
int enough_space;
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index e35d82808bab..5c774ab98252 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -2284,10 +2284,10 @@ static int isp1362_mem_config(struct usb_hcd *hcd)
dev_info(hcd->self.controller, "ISP1362 Memory usage:\n");
dev_info(hcd->self.controller, " ISTL: 2 * %4d: %4d @ $%04x:$%04x\n",
istl_size / 2, istl_size, 0, istl_size / 2);
- dev_info(hcd->self.controller, " INTL: %4d * (%3u+8): %4d @ $%04x\n",
+ dev_info(hcd->self.controller, " INTL: %4d * (%3lu+8): %4d @ $%04x\n",
ISP1362_INTL_BUFFERS, intl_blksize - PTD_HEADER_SIZE,
intl_size, istl_size);
- dev_info(hcd->self.controller, " ATL : %4d * (%3u+8): %4d @ $%04x\n",
+ dev_info(hcd->self.controller, " ATL : %4d * (%3lu+8): %4d @ $%04x\n",
atl_buffers, atl_blksize - PTD_HEADER_SIZE,
atl_size, istl_size + intl_size);
dev_info(hcd->self.controller, " USED/FREE: %4d %4d\n", total,
@@ -2677,12 +2677,12 @@ static int __devexit isp1362_remove(struct platform_device *pdev)
DBG(0, "%s: Removing HCD\n", __func__);
usb_remove_hcd(hcd);
- DBG(0, "%s: Unmapping data_reg @ %08x\n", __func__,
- (u32)isp1362_hcd->data_reg);
+ DBG(0, "%s: Unmapping data_reg @ %p\n", __func__,
+ isp1362_hcd->data_reg);
iounmap(isp1362_hcd->data_reg);
- DBG(0, "%s: Unmapping addr_reg @ %08x\n", __func__,
- (u32)isp1362_hcd->addr_reg);
+ DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__,
+ isp1362_hcd->addr_reg);
iounmap(isp1362_hcd->addr_reg);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
@@ -2810,16 +2810,16 @@ static int __init isp1362_probe(struct platform_device *pdev)
return 0;
err6:
- DBG(0, "%s: Freeing dev %08x\n", __func__, (u32)isp1362_hcd);
+ DBG(0, "%s: Freeing dev %p\n", __func__, isp1362_hcd);
usb_put_hcd(hcd);
err5:
- DBG(0, "%s: Unmapping data_reg @ %08x\n", __func__, (u32)data_reg);
+ DBG(0, "%s: Unmapping data_reg @ %p\n", __func__, data_reg);
iounmap(data_reg);
err4:
DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)data->start);
release_mem_region(data->start, resource_len(data));
err3:
- DBG(0, "%s: Unmapping addr_reg @ %08x\n", __func__, (u32)addr_reg);
+ DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, addr_reg);
iounmap(addr_reg);
err2:
DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)addr->start);
diff --git a/drivers/usb/host/isp1362.h b/drivers/usb/host/isp1362.h
index fe60f62a32f3..1a253ebf7e50 100644
--- a/drivers/usb/host/isp1362.h
+++ b/drivers/usb/host/isp1362.h
@@ -580,7 +580,7 @@ static inline const char *ISP1362_INT_NAME(int n)
static inline void ALIGNSTAT(struct isp1362_hcd *isp1362_hcd, void *ptr)
{
- unsigned p = (unsigned)ptr;
+ unsigned long p = (unsigned long)ptr;
if (!(p & 0xf))
isp1362_hcd->stat16++;
else if (!(p & 0x7))
@@ -770,7 +770,7 @@ static void isp1362_write_fifo(struct isp1362_hcd *isp1362_hcd, void *buf, u16 l
if (!len)
return;
- if ((unsigned)dp & 0x1) {
+ if ((unsigned long)dp & 0x1) {
/* not aligned */
for (; len > 1; len -= 2) {
data = *dp++;
@@ -962,8 +962,8 @@ static void isp1362_read_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16
isp1362_write_diraddr(isp1362_hcd, offset, len);
- DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %08x\n", __func__,
- len, offset, (u32)buf);
+ DBG(3, "%s: Reading %d byte from buffer @%04x to memory @ %p\n",
+ __func__, len, offset, buf);
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
_WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
@@ -982,8 +982,8 @@ static void isp1362_write_buffer(struct isp1362_hcd *isp1362_hcd, void *buf, u16
isp1362_write_diraddr(isp1362_hcd, offset, len);
- DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %08x\n", __func__,
- len, offset, (u32)buf);
+ DBG(3, "%s: Writing %d byte to buffer @%04x from memory @ %p\n",
+ __func__, len, offset, buf);
isp1362_write_reg16(isp1362_hcd, HCuPINT, HCuPINT_EOT);
_WARN_ON((isp1362_read_reg16(isp1362_hcd, HCuPINT) & HCuPINT_EOT));
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 23cf3bde4762..83b5f9cea85a 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -475,4 +475,4 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
quirk_usb_handoff_xhci(pdev);
}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
+DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c
index c632437c7649..562eba108816 100644
--- a/drivers/usb/host/whci/asl.c
+++ b/drivers/usb/host/whci/asl.c
@@ -115,6 +115,10 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset)
if (status & QTD_STS_HALTED) {
/* Ug, an error. */
process_halted_qtd(whc, qset, td);
+ /* A halted qTD always triggers an update
+ because the qset was either removed or
+ reactivated. */
+ update |= WHC_UPDATE_UPDATED;
goto done;
}
@@ -305,6 +309,7 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
struct whc_urb *wurb = urb->hcpriv;
struct whc_qset *qset = wurb->qset;
struct whc_std *std, *t;
+ bool has_qtd = false;
int ret;
unsigned long flags;
@@ -315,17 +320,21 @@ int asl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
goto out;
list_for_each_entry_safe(std, t, &qset->stds, list_node) {
- if (std->urb == urb)
+ if (std->urb == urb) {
+ if (std->qtd)
+ has_qtd = true;
qset_free_std(whc, std);
- else
+ } else
std->qtd = NULL; /* so this std is re-added when the qset is */
}
- asl_qset_remove(whc, qset);
- wurb->status = status;
- wurb->is_async = true;
- queue_work(whc->workqueue, &wurb->dequeue_work);
-
+ if (has_qtd) {
+ asl_qset_remove(whc, qset);
+ wurb->status = status;
+ wurb->is_async = true;
+ queue_work(whc->workqueue, &wurb->dequeue_work);
+ } else
+ qset_remove_urb(whc, qset, urb, status);
out:
spin_unlock_irqrestore(&whc->lock, flags);
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c
index a9e05bac6646..0db3fb2dc03a 100644
--- a/drivers/usb/host/whci/pzl.c
+++ b/drivers/usb/host/whci/pzl.c
@@ -121,6 +121,10 @@ static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
if (status & QTD_STS_HALTED) {
/* Ug, an error. */
process_halted_qtd(whc, qset, td);
+ /* A halted qTD always triggers an update
+ because the qset was either removed or
+ reactivated. */
+ update |= WHC_UPDATE_UPDATED;
goto done;
}
@@ -333,6 +337,7 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
struct whc_urb *wurb = urb->hcpriv;
struct whc_qset *qset = wurb->qset;
struct whc_std *std, *t;
+ bool has_qtd = false;
int ret;
unsigned long flags;
@@ -343,17 +348,22 @@ int pzl_urb_dequeue(struct whc *whc, struct urb *urb, int status)
goto out;
list_for_each_entry_safe(std, t, &qset->stds, list_node) {
- if (std->urb == urb)
+ if (std->urb == urb) {
+ if (std->qtd)
+ has_qtd = true;
qset_free_std(whc, std);
- else
+ } else
std->qtd = NULL; /* so this std is re-added when the qset is */
}
- pzl_qset_remove(whc, qset);
- wurb->status = status;
- wurb->is_async = false;
- queue_work(whc->workqueue, &wurb->dequeue_work);
-
+ if (has_qtd) {
+ pzl_qset_remove(whc, qset);
+ update_pzl_hw_view(whc);
+ wurb->status = status;
+ wurb->is_async = false;
+ queue_work(whc->workqueue, &wurb->dequeue_work);
+ } else
+ qset_remove_urb(whc, qset, urb, status);
out:
spin_unlock_irqrestore(&whc->lock, flags);
diff --git a/drivers/usb/host/xhci-hcd.c b/drivers/usb/host/xhci-hcd.c
index 99911e727e0b..932f99938481 100644
--- a/drivers/usb/host/xhci-hcd.c
+++ b/drivers/usb/host/xhci-hcd.c
@@ -335,6 +335,12 @@ void xhci_event_ring_work(unsigned long arg)
spin_lock_irqsave(&xhci->lock, flags);
temp = xhci_readl(xhci, &xhci->op_regs->status);
xhci_dbg(xhci, "op reg status = 0x%x\n", temp);
+ if (temp == 0xffffffff) {
+ xhci_dbg(xhci, "HW died, polling stopped.\n");
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return;
+ }
+
temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
xhci_dbg(xhci, "ir_set 0 pending = 0x%x\n", temp);
xhci_dbg(xhci, "No-op commands handled = %d\n", xhci->noops_handled);
@@ -776,6 +782,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
unsigned long flags;
int ret;
+ u32 temp;
struct xhci_hcd *xhci;
struct xhci_td *td;
unsigned int ep_index;
@@ -788,6 +795,17 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
ret = usb_hcd_check_unlink_urb(hcd, urb, status);
if (ret || !urb->hcpriv)
goto done;
+ temp = xhci_readl(xhci, &xhci->op_regs->status);
+ if (temp == 0xffffffff) {
+ xhci_dbg(xhci, "HW died, freeing TD.\n");
+ td = (struct xhci_td *) urb->hcpriv;
+
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN);
+ kfree(td);
+ return ret;
+ }
xhci_dbg(xhci, "Cancel URB %p\n", urb);
xhci_dbg(xhci, "Event ring:\n");
@@ -877,7 +895,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
ctrl_ctx->drop_flags |= drop_flag;
new_drop_flags = ctrl_ctx->drop_flags;
- ctrl_ctx->add_flags = ~drop_flag;
+ ctrl_ctx->add_flags &= ~drop_flag;
new_add_flags = ctrl_ctx->add_flags;
last_ctx = xhci_last_valid_endpoint(ctrl_ctx->add_flags);
@@ -1410,11 +1428,20 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
unsigned long flags;
+ u32 state;
if (udev->slot_id == 0)
return;
spin_lock_irqsave(&xhci->lock, flags);
+ /* Don't disable the slot if the host controller is dead. */
+ state = xhci_readl(xhci, &xhci->op_regs->status);
+ if (state == 0xffffffff) {
+ xhci_free_virt_device(xhci, udev->slot_id);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ return;
+ }
+
if (xhci_queue_slot_control(xhci, TRB_DISABLE_SLOT, udev->slot_id)) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 29092b8e59ce..4fb120357c55 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -313,7 +313,8 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
if (le16_to_cpu(dev->udev->descriptor.idProduct) != 0x0001) {
dev_warn(&interface->dev, "USBLCD model not supported.\n");
- return -ENODEV;
+ retval = -ENODEV;
+ goto error;
}
/* set up the endpoint information */
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 803adcb5ac1d..b84abd8ee8a5 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -8,8 +8,8 @@ comment "Enable Host or Gadget support to see Inventra options"
# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
config USB_MUSB_HDRC
- depends on (USB || USB_GADGET) && HAVE_CLK
- depends on !SUPERH
+ depends on (USB || USB_GADGET)
+ depends on (ARM || BLACKFIN)
select NOP_USB_XCEIV if ARCH_DAVINCI
select TWL4030_USB if MACH_OMAP_3430SDP
select NOP_USB_XCEIV if MACH_OMAP3EVM
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index f2f66ebc7362..fcec87ea709e 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -14,7 +14,6 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
-#include <linux/clk.h>
#include <linux/gpio.h>
#include <linux/io.h>
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 381d648a36b8..6aa5f22e5274 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -95,6 +95,13 @@ struct musb_ep;
#endif
#endif /* need MUSB gadget selection */
+#ifndef CONFIG_HAVE_CLK
+/* Dummy stub for clk framework */
+#define clk_get(dev, id) NULL
+#define clk_put(clock) do {} while (0)
+#define clk_enable(clock) do {} while (0)
+#define clk_disable(clock) do {} while (0)
+#endif
#ifdef CONFIG_PROC_FS
#include <linux/fs.h>
diff --git a/drivers/usb/musb/musb_regs.h b/drivers/usb/musb/musb_regs.h
index fbfd3fd9ce1f..cc1d71b57d3c 100644
--- a/drivers/usb/musb/musb_regs.h
+++ b/drivers/usb/musb/musb_regs.h
@@ -439,15 +439,6 @@ static inline void musb_write_txhubport(void __iomem *mbase, u8 epnum,
/* Not implemented - HW has seperate Tx/Rx FIFO */
#define MUSB_TXCSR_MODE 0x0000
-/*
- * Dummy stub for clk framework, it will be removed
- * until Blackfin supports clk framework
- */
-#define clk_get(dev, id) NULL
-#define clk_put(clock) do {} while (0)
-#define clk_enable(clock) do {} while (0)
-#define clk_disable(clock) do {} while (0)
-
static inline void musb_write_txfifosz(void __iomem *mbase, u8 c_size)
{
}
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 2cbfab3716e5..b10ac8409411 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -554,13 +554,12 @@ static void aircable_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct aircable_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->rx_lock, flags);
+ spin_lock_irq(&priv->rx_lock);
priv->rx_flags |= THROTTLED;
- spin_unlock_irqrestore(&priv->rx_lock, flags);
+ spin_unlock_irq(&priv->rx_lock);
}
/* Based on ftdi_sio.c unthrottle */
@@ -569,14 +568,13 @@ static void aircable_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct aircable_private *priv = usb_get_serial_port_data(port);
int actually_throttled;
- unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->rx_lock, flags);
+ spin_lock_irq(&priv->rx_lock);
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
- spin_unlock_irqrestore(&priv->rx_lock, flags);
+ spin_unlock_irq(&priv->rx_lock);
if (actually_throttled)
schedule_work(&priv->rx_work);
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 4a208fe85bc9..698252a4dc5d 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -113,6 +113,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x166A, 0x0303) }, /* Clipsal 5500PCU C-Bus USB interface */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ USB_DEVICE(0x18EF, 0xE00F) }, /* ELV USB-I2C-Interface */
+ { USB_DEVICE(0x413C, 0x9500) }, /* DW700 GPS USB interface */
{ } /* Terminating Entry */
};
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index e0a8b715f2f2..a591ebec0f89 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -1155,13 +1155,12 @@ static void cypress_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
priv->rx_flags = THROTTLED;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
}
@@ -1170,14 +1169,13 @@ static void cypress_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct cypress_private *priv = usb_get_serial_port_data(port);
int actually_throttled, result;
- unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
priv->rx_flags = 0;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
if (!priv->comm_is_ok)
return;
@@ -1185,7 +1183,7 @@ static void cypress_unthrottle(struct tty_struct *tty)
if (actually_throttled) {
port->interrupt_in_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
dev_err(&port->dev, "%s - failed submitting read urb, "
"error %d\n", __func__, result);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index ab3dd991586b..68e80be6b9e1 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -898,16 +898,16 @@ static void digi_rx_unthrottle(struct tty_struct *tty)
spin_lock_irqsave(&priv->dp_port_lock, flags);
- /* turn throttle off */
- priv->dp_throttled = 0;
- priv->dp_throttle_restart = 0;
-
/* restart read chain */
if (priv->dp_throttle_restart) {
port->read_urb->dev = port->serial->dev;
ret = usb_submit_urb(port->read_urb, GFP_ATOMIC);
}
+ /* turn throttle off */
+ priv->dp_throttled = 0;
+ priv->dp_throttle_restart = 0;
+
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
if (ret)
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 33c9e9cf9eb2..7dd0e3eadbe6 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -391,7 +391,7 @@ static void empeg_unthrottle(struct tty_struct *tty)
dbg("%s - port %d", __func__, port->number);
port->read_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
"%s - failed submitting read urb, error %d\n",
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 4f883b1773d0..9c60d6d4908a 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -76,13 +76,7 @@ struct ftdi_private {
unsigned long last_dtr_rts; /* saved modem control outputs */
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
char prev_status, diff_status; /* Used for TIOCMIWAIT */
- __u8 rx_flags; /* receive state flags (throttling) */
- spinlock_t rx_lock; /* spinlock for receive state */
- struct delayed_work rx_work;
struct usb_serial_port *port;
- int rx_processed;
- unsigned long rx_bytes;
-
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
(0 for FT232/245) */
@@ -737,10 +731,6 @@ static const char *ftdi_chip_name[] = {
/* Constants for read urb and write urb */
#define BUFSZ 512
-/* rx_flags */
-#define THROTTLED 0x01
-#define ACTUALLY_THROTTLED 0x02
-
/* Used for TIOCMIWAIT */
#define FTDI_STATUS_B0_MASK (FTDI_RS0_CTS | FTDI_RS0_DSR | FTDI_RS0_RI | FTDI_RS0_RLSD)
#define FTDI_STATUS_B1_MASK (FTDI_RS_BI)
@@ -763,7 +753,7 @@ static int ftdi_write_room(struct tty_struct *tty);
static int ftdi_chars_in_buffer(struct tty_struct *tty);
static void ftdi_write_bulk_callback(struct urb *urb);
static void ftdi_read_bulk_callback(struct urb *urb);
-static void ftdi_process_read(struct work_struct *work);
+static void ftdi_process_read(struct usb_serial_port *port);
static void ftdi_set_termios(struct tty_struct *tty,
struct usb_serial_port *port, struct ktermios *old);
static int ftdi_tiocmget(struct tty_struct *tty, struct file *file);
@@ -1234,7 +1224,6 @@ static int set_serial_info(struct tty_struct *tty,
(new_serial.flags & ASYNC_FLAGS));
priv->custom_divisor = new_serial.custom_divisor;
- tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
write_latency_timer(port);
check_and_exit:
@@ -1527,7 +1516,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
}
kref_init(&priv->kref);
- spin_lock_init(&priv->rx_lock);
spin_lock_init(&priv->tx_lock);
init_waitqueue_head(&priv->delta_msr_wait);
/* This will push the characters through immediately rather
@@ -1549,7 +1537,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
port->read_urb->transfer_buffer_length = BUFSZ;
}
- INIT_DELAYED_WORK(&priv->rx_work, ftdi_process_read);
priv->port = port;
/* Free port's existing write urb and transfer buffer. */
@@ -1686,6 +1673,26 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
return 0;
}
+static int ftdi_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
+{
+ struct urb *urb = port->read_urb;
+ struct usb_serial *serial = port->serial;
+ int result;
+
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ urb->transfer_buffer,
+ urb->transfer_buffer_length,
+ ftdi_read_bulk_callback, port);
+ result = usb_submit_urb(urb, mem_flags);
+ if (result)
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
+ __func__, result);
+ return result;
+}
+
static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
{ /* ftdi_open */
struct usb_device *dev = port->serial->dev;
@@ -1700,12 +1707,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
spin_lock_irqsave(&priv->tx_lock, flags);
priv->tx_bytes = 0;
spin_unlock_irqrestore(&priv->tx_lock, flags);
- spin_lock_irqsave(&priv->rx_lock, flags);
- priv->rx_bytes = 0;
- spin_unlock_irqrestore(&priv->rx_lock, flags);
-
- if (tty)
- tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
write_latency_timer(port);
@@ -1725,23 +1726,14 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
ftdi_set_termios(tty, port, tty->termios);
/* Not throttled */
- spin_lock_irqsave(&priv->rx_lock, flags);
- priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
- spin_unlock_irqrestore(&priv->rx_lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ port->throttled = 0;
+ port->throttle_req = 0;
+ spin_unlock_irqrestore(&port->lock, flags);
/* Start reading from the device */
- priv->rx_processed = 0;
- usb_fill_bulk_urb(port->read_urb, dev,
- usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- ftdi_read_bulk_callback, port);
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result)
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
- __func__, result);
- else
+ result = ftdi_submit_read_urb(port, GFP_KERNEL);
+ if (!result)
kref_get(&priv->kref);
return result;
@@ -1787,10 +1779,6 @@ static void ftdi_close(struct usb_serial_port *port)
dbg("%s", __func__);
-
- /* cancel any scheduled reading */
- cancel_delayed_work_sync(&priv->rx_work);
-
/* shutdown our bulk read */
usb_kill_urb(port->read_urb);
kref_put(&priv->kref, ftdi_sio_priv_release);
@@ -2013,271 +2001,121 @@ static int ftdi_chars_in_buffer(struct tty_struct *tty)
return buffered;
}
-static void ftdi_read_bulk_callback(struct urb *urb)
+static int ftdi_process_packet(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ftdi_private *priv,
+ char *packet, int len)
{
- struct usb_serial_port *port = urb->context;
- struct tty_struct *tty;
- struct ftdi_private *priv;
- unsigned long countread;
- unsigned long flags;
- int status = urb->status;
-
- if (urb->number_of_packets > 0) {
- dev_err(&port->dev, "%s transfer_buffer_length %d "
- "actual_length %d number of packets %d\n", __func__,
- urb->transfer_buffer_length,
- urb->actual_length, urb->number_of_packets);
- dev_err(&port->dev, "%s transfer_flags %x\n", __func__,
- urb->transfer_flags);
- }
+ int i;
+ char status;
+ char flag;
+ char *ch;
dbg("%s - port %d", __func__, port->number);
- if (port->port.count <= 0)
- return;
-
- tty = tty_port_tty_get(&port->port);
- if (!tty) {
- dbg("%s - bad tty pointer - exiting", __func__);
- return;
+ if (len < 2) {
+ dbg("malformed packet");
+ return 0;
}
- priv = usb_get_serial_port_data(port);
- if (!priv) {
- dbg("%s - bad port private data pointer - exiting", __func__);
- goto out;
+ /* Compare new line status to the old one, signal if different/
+ N.B. packet may be processed more than once, but differences
+ are only processed once. */
+ status = packet[0] & FTDI_STATUS_B0_MASK;
+ if (status != priv->prev_status) {
+ priv->diff_status |= status ^ priv->prev_status;
+ wake_up_interruptible(&priv->delta_msr_wait);
+ priv->prev_status = status;
}
- if (urb != port->read_urb)
- dev_err(&port->dev, "%s - Not my urb!\n", __func__);
-
- if (status) {
- /* This will happen at close every time so it is a dbg not an
- err */
- dbg("(this is ok on close) nonzero read bulk status received: %d", status);
- goto out;
+ /*
+ * Although the device uses a bitmask and hence can have multiple
+ * errors on a packet - the order here sets the priority the error is
+ * returned to the tty layer.
+ */
+ flag = TTY_NORMAL;
+ if (packet[1] & FTDI_RS_OE) {
+ flag = TTY_OVERRUN;
+ dbg("OVERRRUN error");
+ }
+ if (packet[1] & FTDI_RS_BI) {
+ flag = TTY_BREAK;
+ dbg("BREAK received");
+ usb_serial_handle_break(port);
+ }
+ if (packet[1] & FTDI_RS_PE) {
+ flag = TTY_PARITY;
+ dbg("PARITY error");
+ }
+ if (packet[1] & FTDI_RS_FE) {
+ flag = TTY_FRAME;
+ dbg("FRAMING error");
}
- /* count data bytes, but not status bytes */
- countread = urb->actual_length;
- countread -= 2 * DIV_ROUND_UP(countread, priv->max_packet_size);
- spin_lock_irqsave(&priv->rx_lock, flags);
- priv->rx_bytes += countread;
- spin_unlock_irqrestore(&priv->rx_lock, flags);
-
- ftdi_process_read(&priv->rx_work.work);
-out:
- tty_kref_put(tty);
-} /* ftdi_read_bulk_callback */
-
+ len -= 2;
+ if (!len)
+ return 0; /* status only */
+ ch = packet + 2;
+
+ if (!(port->console && port->sysrq) && flag == TTY_NORMAL)
+ tty_insert_flip_string(tty, ch, len);
+ else {
+ for (i = 0; i < len; i++, ch++) {
+ if (!usb_serial_handle_sysrq_char(tty, port, *ch))
+ tty_insert_flip_char(tty, *ch, flag);
+ }
+ }
+ return len;
+}
-static void ftdi_process_read(struct work_struct *work)
-{ /* ftdi_process_read */
- struct ftdi_private *priv =
- container_of(work, struct ftdi_private, rx_work.work);
- struct usb_serial_port *port = priv->port;
- struct urb *urb;
+static void ftdi_process_read(struct usb_serial_port *port)
+{
+ struct urb *urb = port->read_urb;
struct tty_struct *tty;
- char error_flag;
- unsigned char *data;
-
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ char *data = (char *)urb->transfer_buffer;
int i;
- int result;
- int need_flip;
- int packet_offset;
- unsigned long flags;
-
- dbg("%s - port %d", __func__, port->number);
-
- if (port->port.count <= 0)
- return;
+ int len;
+ int count = 0;
tty = tty_port_tty_get(&port->port);
- if (!tty) {
- dbg("%s - bad tty pointer - exiting", __func__);
+ if (!tty)
return;
- }
-
- priv = usb_get_serial_port_data(port);
- if (!priv) {
- dbg("%s - bad port private data pointer - exiting", __func__);
- goto out;
- }
-
- urb = port->read_urb;
- if (!urb) {
- dbg("%s - bad read_urb pointer - exiting", __func__);
- goto out;
- }
-
- data = urb->transfer_buffer;
- if (priv->rx_processed) {
- dbg("%s - already processed: %d bytes, %d remain", __func__,
- priv->rx_processed,
- urb->actual_length - priv->rx_processed);
- } else {
- /* The first two bytes of every read packet are status */
- if (urb->actual_length > 2)
- usb_serial_debug_data(debug, &port->dev, __func__,
- urb->actual_length, data);
- else
- dbg("Status only: %03oo %03oo", data[0], data[1]);
+ for (i = 0; i < urb->actual_length; i += priv->max_packet_size) {
+ len = min_t(int, urb->actual_length - i, priv->max_packet_size);
+ count += ftdi_process_packet(tty, port, priv, &data[i], len);
}
-
- /* TO DO -- check for hung up line and handle appropriately: */
- /* send hangup */
- /* See acm.c - you do a tty_hangup - eg tty_hangup(tty) */
- /* if CD is dropped and the line is not CLOCAL then we should hangup */
-
- need_flip = 0;
- for (packet_offset = priv->rx_processed;
- packet_offset < urb->actual_length; packet_offset += priv->max_packet_size) {
- int length;
-
- /* Compare new line status to the old one, signal if different/
- N.B. packet may be processed more than once, but differences
- are only processed once. */
- char new_status = data[packet_offset + 0] &
- FTDI_STATUS_B0_MASK;
- if (new_status != priv->prev_status) {
- priv->diff_status |=
- new_status ^ priv->prev_status;
- wake_up_interruptible(&priv->delta_msr_wait);
- priv->prev_status = new_status;
- }
-
- length = min_t(u32, priv->max_packet_size, urb->actual_length-packet_offset)-2;
- if (length < 0) {
- dev_err(&port->dev, "%s - bad packet length: %d\n",
- __func__, length+2);
- length = 0;
- }
-
- if (priv->rx_flags & THROTTLED) {
- dbg("%s - throttled", __func__);
- break;
- }
- if (tty_buffer_request_room(tty, length) < length) {
- /* break out & wait for throttling/unthrottling to
- happen */
- dbg("%s - receive room low", __func__);
- break;
- }
-
- /* Handle errors and break */
- error_flag = TTY_NORMAL;
- /* Although the device uses a bitmask and hence can have
- multiple errors on a packet - the order here sets the
- priority the error is returned to the tty layer */
-
- if (data[packet_offset+1] & FTDI_RS_OE) {
- error_flag = TTY_OVERRUN;
- dbg("OVERRRUN error");
- }
- if (data[packet_offset+1] & FTDI_RS_BI) {
- error_flag = TTY_BREAK;
- dbg("BREAK received");
- usb_serial_handle_break(port);
- }
- if (data[packet_offset+1] & FTDI_RS_PE) {
- error_flag = TTY_PARITY;
- dbg("PARITY error");
- }
- if (data[packet_offset+1] & FTDI_RS_FE) {
- error_flag = TTY_FRAME;
- dbg("FRAMING error");
- }
- if (length > 0) {
- for (i = 2; i < length+2; i++) {
- /* Note that the error flag is duplicated for
- every character received since we don't know
- which character it applied to */
- if (!usb_serial_handle_sysrq_char(tty, port,
- data[packet_offset + i]))
- tty_insert_flip_char(tty,
- data[packet_offset + i],
- error_flag);
- }
- need_flip = 1;
- }
-
-#ifdef NOT_CORRECT_BUT_KEEPING_IT_FOR_NOW
- /* if a parity error is detected you get status packets forever
- until a character is sent without a parity error.
- This doesn't work well since the application receives a
- never ending stream of bad data - even though new data
- hasn't been sent. Therefore I (bill) have taken this out.
- However - this might make sense for framing errors and so on
- so I am leaving the code in for now.
- */
- else {
- if (error_flag != TTY_NORMAL) {
- dbg("error_flag is not normal");
- /* In this case it is just status - if that is
- an error send a bad character */
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- tty_flip_buffer_push(tty);
- tty_insert_flip_char(tty, 0xff, error_flag);
- need_flip = 1;
- }
- }
-#endif
- } /* "for(packet_offset=0..." */
-
- /* Low latency */
- if (need_flip)
+ if (count)
tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+}
- if (packet_offset < urb->actual_length) {
- /* not completely processed - record progress */
- priv->rx_processed = packet_offset;
- dbg("%s - incomplete, %d bytes processed, %d remain",
- __func__, packet_offset,
- urb->actual_length - packet_offset);
- /* check if we were throttled while processing */
- spin_lock_irqsave(&priv->rx_lock, flags);
- if (priv->rx_flags & THROTTLED) {
- priv->rx_flags |= ACTUALLY_THROTTLED;
- spin_unlock_irqrestore(&priv->rx_lock, flags);
- dbg("%s - deferring remainder until unthrottled",
- __func__);
- goto out;
- }
- spin_unlock_irqrestore(&priv->rx_lock, flags);
- /* if the port is closed stop trying to read */
- if (port->port.count > 0)
- /* delay processing of remainder */
- schedule_delayed_work(&priv->rx_work, 1);
- else
- dbg("%s - port is closed", __func__);
- goto out;
- }
-
- /* urb is completely processed */
- priv->rx_processed = 0;
+static void ftdi_read_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ unsigned long flags;
- /* if the port is closed stop trying to read */
- if (port->port.count > 0) {
- /* Continue trying to always read */
- usb_fill_bulk_urb(port->read_urb, port->serial->dev,
- usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- ftdi_read_bulk_callback, port);
+ dbg("%s - port %d", __func__, port->number);
- result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
- if (result)
- dev_err(&port->dev,
- "%s - failed resubmitting read urb, error %d\n",
- __func__, result);
+ if (urb->status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __func__, urb->status);
+ return;
}
-out:
- tty_kref_put(tty);
-} /* ftdi_process_read */
+ usb_serial_debug_data(debug, &port->dev, __func__,
+ urb->actual_length, urb->transfer_buffer);
+ ftdi_process_read(port);
+
+ spin_lock_irqsave(&port->lock, flags);
+ port->throttled = port->throttle_req;
+ if (!port->throttled) {
+ spin_unlock_irqrestore(&port->lock, flags);
+ ftdi_submit_read_urb(port, GFP_ATOMIC);
+ } else
+ spin_unlock_irqrestore(&port->lock, flags);
+}
static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
{
@@ -2609,33 +2447,31 @@ static int ftdi_ioctl(struct tty_struct *tty, struct file *file,
static void ftdi_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->rx_lock, flags);
- priv->rx_flags |= THROTTLED;
- spin_unlock_irqrestore(&priv->rx_lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ port->throttle_req = 1;
+ spin_unlock_irqrestore(&port->lock, flags);
}
-
-static void ftdi_unthrottle(struct tty_struct *tty)
+void ftdi_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- struct ftdi_private *priv = usb_get_serial_port_data(port);
- int actually_throttled;
+ int was_throttled;
unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->rx_lock, flags);
- actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
- priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
- spin_unlock_irqrestore(&priv->rx_lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ was_throttled = port->throttled;
+ port->throttled = port->throttle_req = 0;
+ spin_unlock_irqrestore(&port->lock, flags);
- if (actually_throttled)
- schedule_delayed_work(&priv->rx_work, 0);
+ /* Resubmit urb if throttled and open. */
+ if (was_throttled && test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+ ftdi_submit_read_urb(port, GFP_KERNEL);
}
static int __init ftdi_init(void)
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 20432d345529..5ac900e5a50e 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1390,14 +1390,13 @@ static void garmin_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
- unsigned long flags;
dbg("%s - port %d", __func__, port->number);
/* set flag, data received will be put into a queue
for later processing */
- spin_lock_irqsave(&garmin_data_p->lock, flags);
+ spin_lock_irq(&garmin_data_p->lock);
garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED;
- spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ spin_unlock_irq(&garmin_data_p->lock);
}
@@ -1405,13 +1404,12 @@ static void garmin_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
- unsigned long flags;
int status;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&garmin_data_p->lock, flags);
+ spin_lock_irq(&garmin_data_p->lock);
garmin_data_p->flags &= ~FLAGS_THROTTLED;
- spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ spin_unlock_irq(&garmin_data_p->lock);
/* in native mode send queued data to tty, in
serial mode nothing needs to be done here */
@@ -1419,7 +1417,7 @@ static void garmin_unthrottle(struct tty_struct *tty)
garmin_flush_queue(garmin_data_p);
if (0 != (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
- status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ status = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (status)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index deba08c7a015..bbe005cefcfb 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -546,7 +546,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
if (was_throttled) {
/* Resume reading from device */
- usb_serial_generic_resubmit_read_urb(port, GFP_KERNEL);
+ flush_and_resubmit_read_urb(port);
}
}
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 24fcc64b837d..d6231c38813e 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -966,6 +966,15 @@ static int ipaq_calc_num_ports(struct usb_serial *serial)
static int ipaq_startup(struct usb_serial *serial)
{
dbg("%s", __func__);
+
+ /* Some of the devices in ipaq_id_table[] are composite, and we
+ * shouldn't bind to all the interfaces. This test will rule out
+ * some obviously invalid possibilities.
+ */
+ if (serial->num_bulk_in < serial->num_ports ||
+ serial->num_bulk_out < serial->num_ports)
+ return -ENODEV;
+
if (serial->dev->actconfig->desc.bConfigurationValue != 1) {
/*
* FIXME: HP iPaq rx3715, possibly others, have 1 config that
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 257c16cc6b2a..1296a097f5c3 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -290,7 +290,7 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
/* just restart the receive interrupt URB */
dbg("keyspan_pda_rx_unthrottle port %d", port->number);
port->interrupt_in_urb->dev = port->serial->dev;
- if (usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC))
+ if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
dbg(" usb_submit_urb(read urb) failed");
return;
}
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index f7373371b137..3a7873806f46 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -951,7 +951,7 @@ static void klsi_105_unthrottle(struct tty_struct *tty)
dbg("%s - port %d", __func__, port->number);
port->read_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result)
dev_err(&port->dev,
"%s - failed submitting read urb, error %d\n",
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index ad4998bbf16f..cd009cb280a5 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -777,20 +777,19 @@ static void mct_u232_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
unsigned int control_state;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
priv->rx_flags |= THROTTLED;
if (C_CRTSCTS(tty)) {
priv->control_state &= ~TIOCM_RTS;
control_state = priv->control_state;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
(void) mct_u232_set_modem_ctrl(port->serial, control_state);
} else {
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
}
}
@@ -799,20 +798,19 @@ static void mct_u232_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
unsigned int control_state;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) {
priv->rx_flags &= ~THROTTLED;
priv->control_state |= TIOCM_RTS;
control_state = priv->control_state;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
(void) mct_u232_set_modem_ctrl(port->serial, control_state);
} else {
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
}
}
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 1085a577c5c1..80f59b6350cb 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -314,21 +314,24 @@ static void opticon_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct opticon_private *priv = usb_get_serial_data(port->serial);
unsigned long flags;
- int result;
+ int result, was_throttled;
dbg("%s - port %d", __func__, port->number);
spin_lock_irqsave(&priv->lock, flags);
priv->throttled = false;
+ was_throttled = priv->actually_throttled;
priv->actually_throttled = false;
spin_unlock_irqrestore(&priv->lock, flags);
priv->bulk_read_urb->dev = port->serial->dev;
- result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC);
- if (result)
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
+ if (was_throttled) {
+ result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
__func__, result);
+ }
}
static int opticon_tiocmget(struct tty_struct *tty, struct file *file)
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index f66e39883218..65d96b214f95 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -165,6 +165,7 @@ static int option_resume(struct usb_serial *serial);
#define HUAWEI_PRODUCT_E143D 0x143D
#define HUAWEI_PRODUCT_E143E 0x143E
#define HUAWEI_PRODUCT_E143F 0x143F
+#define HUAWEI_PRODUCT_E14AC 0x14AC
#define QUANTA_VENDOR_ID 0x0408
#define QUANTA_PRODUCT_Q101 0xEA02
@@ -318,6 +319,7 @@ static int option_resume(struct usb_serial *serial);
/* TOSHIBA PRODUCTS */
#define TOSHIBA_VENDOR_ID 0x0930
#define TOSHIBA_PRODUCT_HSDPA_MINICARD 0x1302
+#define TOSHIBA_PRODUCT_G450 0x0d45
#define ALINK_VENDOR_ID 0x1e0e
#define ALINK_PRODUCT_3GU 0x9200
@@ -326,6 +328,9 @@ static int option_resume(struct usb_serial *serial);
#define ALCATEL_VENDOR_ID 0x1bbb
#define ALCATEL_PRODUCT_X060S 0x0000
+/* Airplus products */
+#define AIRPLUS_VENDOR_ID 0x1011
+#define AIRPLUS_PRODUCT_MCD650 0x3198
static struct usb_device_id option_ids[] = {
{ USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@@ -424,6 +429,7 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143D, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143E, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E143F, 0xff, 0xff, 0xff) },
+ { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_E14AC) },
{ USB_DEVICE(AMOI_VENDOR_ID, AMOI_PRODUCT_9508) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V640) }, /* Novatel Merlin V640/XV620 */
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_V620) }, /* Novatel Merlin V620/S620 */
@@ -581,10 +587,12 @@ static struct usb_device_id option_ids[] = {
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H21_4523) },
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4515) },
{ USB_DEVICE(QISDA_VENDOR_ID, QISDA_PRODUCT_H20_4519) },
+ { USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_G450) },
{ USB_DEVICE(TOSHIBA_VENDOR_ID, TOSHIBA_PRODUCT_HSDPA_MINICARD ) }, /* Toshiba 3G HSDPA == Novatel Expedite EU870D MiniCard */
{ USB_DEVICE(ALINK_VENDOR_ID, 0x9000) },
{ USB_DEVICE_AND_INTERFACE_INFO(ALINK_VENDOR_ID, ALINK_PRODUCT_3GU, 0xff, 0xff, 0xff) },
{ USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) },
+ { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 0f4a70ce3823..c644e26394b4 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -288,7 +288,7 @@ static void setup_line(struct work_struct *work)
dbg("%s(): submitting interrupt urb", __func__);
port->interrupt_in_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result != 0) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
" with error %d\n", __func__, result);
@@ -335,7 +335,7 @@ void send_data(struct work_struct *work)
dbg("%s(): submitting interrupt urb", __func__);
port->interrupt_in_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
if (result != 0) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
" with error %d\n", __func__, result);
@@ -349,7 +349,7 @@ void send_data(struct work_struct *work)
port->write_urb->transfer_buffer_length = count;
port->write_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->write_urb, GFP_NOIO);
if (result != 0) {
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
" with error %d\n", __func__, result);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 1128e01525b1..9ec1a49e2362 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -1046,13 +1046,15 @@ static void pl2303_push_data(struct tty_struct *tty,
/* overrun is special, not associated with a char */
if (line_status & UART_OVERRUN_ERROR)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
- if (port->console && port->sysrq) {
+
+ if (tty_flag == TTY_NORMAL && !(port->console && port->sysrq))
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ else {
int i;
for (i = 0; i < urb->actual_length; ++i)
if (!usb_serial_handle_sysrq_char(tty, port, data[i]))
tty_insert_flip_char(tty, data[i], tty_flag);
- } else
- tty_insert_flip_string(tty, data, urb->actual_length);
+ }
tty_flip_buffer_push(tty);
}
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 8c075b2416bb..45883988a005 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -17,7 +17,7 @@
Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
*/
-#define DRIVER_VERSION "v.1.3.7"
+#define DRIVER_VERSION "v.1.3.8"
#define DRIVER_AUTHOR "Kevin Lloyd, Elina Pasheva, Matthew Safar, Rory Filer"
#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index cb7e95f9fcbf..b282c0f2d8e5 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -165,34 +165,36 @@ static void symbol_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct symbol_private *priv = usb_get_serial_data(port->serial);
- unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
priv->throttled = true;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
}
static void symbol_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct symbol_private *priv = usb_get_serial_data(port->serial);
- unsigned long flags;
int result;
+ bool was_throttled;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
priv->throttled = false;
+ was_throttled = priv->actually_throttled;
priv->actually_throttled = false;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
priv->int_urb->dev = port->serial->dev;
- result = usb_submit_urb(priv->int_urb, GFP_ATOMIC);
- if (result)
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
+ if (was_throttled) {
+ result = usb_submit_urb(priv->int_urb, GFP_KERNEL);
+ if (result)
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
__func__, result);
+ }
}
static int symbol_startup(struct usb_serial *serial)
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index aa6b2ae951ae..bd3fa7ff15b1 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -156,7 +156,8 @@ static void destroy_serial(struct kref *kref)
if (serial->minor != SERIAL_TTY_NO_MINOR)
return_serial(serial);
- serial->type->release(serial);
+ if (serial->attached)
+ serial->type->release(serial);
/* Now that nothing is using the ports, they can be freed */
for (i = 0; i < serial->num_port_pointers; ++i) {
@@ -1059,12 +1060,15 @@ int usb_serial_probe(struct usb_interface *interface,
module_put(type->driver.owner);
if (retval < 0)
goto probe_error;
+ serial->attached = 1;
if (retval > 0) {
/* quietly accept this device, but don't bind to a
serial port as it's about to disappear */
serial->num_ports = 0;
goto exit;
}
+ } else {
+ serial->attached = 1;
}
if (get_free_serial(serial, num_ports, &minor) == NULL) {
@@ -1164,8 +1168,10 @@ int usb_serial_suspend(struct usb_interface *intf, pm_message_t message)
if (serial->type->suspend) {
r = serial->type->suspend(serial, message);
- if (r < 0)
+ if (r < 0) {
+ serial->suspending = 0;
goto err_out;
+ }
}
for (i = 0; i < serial->num_ports; ++i) {
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 1aa5d20a5d99..ad1f9232292d 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -513,7 +513,8 @@ static void visor_read_bulk_callback(struct urb *urb)
tty_kref_put(tty);
}
spin_lock(&priv->lock);
- priv->bytes_in += available_room;
+ if (tty)
+ priv->bytes_in += available_room;
} else {
spin_lock(&priv->lock);
@@ -582,12 +583,11 @@ static void visor_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct visor_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
priv->throttled = 1;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
}
@@ -595,21 +595,23 @@ static void visor_unthrottle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct visor_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- int result;
+ int result, was_throttled;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&priv->lock, flags);
+ spin_lock_irq(&priv->lock);
priv->throttled = 0;
+ was_throttled = priv->actually_throttled;
priv->actually_throttled = 0;
- spin_unlock_irqrestore(&priv->lock, flags);
+ spin_unlock_irq(&priv->lock);
- port->read_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
- if (result)
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
+ if (was_throttled) {
+ port->read_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (result)
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
__func__, result);
+ }
}
static int palm_os_3_probe(struct usb_serial *serial,
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 62424eec33ec..1093d2eb046a 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -949,13 +949,12 @@ static void whiteheat_throttle(struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
struct whiteheat_private *info = usb_get_serial_port_data(port);
- unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&info->lock, flags);
+ spin_lock_irq(&info->lock);
info->flags |= THROTTLED;
- spin_unlock_irqrestore(&info->lock, flags);
+ spin_unlock_irq(&info->lock);
return;
}
@@ -966,14 +965,13 @@ static void whiteheat_unthrottle(struct tty_struct *tty)
struct usb_serial_port *port = tty->driver_data;
struct whiteheat_private *info = usb_get_serial_port_data(port);
int actually_throttled;
- unsigned long flags;
dbg("%s - port %d", __func__, port->number);
- spin_lock_irqsave(&info->lock, flags);
+ spin_lock_irq(&info->lock);
actually_throttled = info->flags & ACTUALLY_THROTTLED;
info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
- spin_unlock_irqrestore(&info->lock, flags);
+ spin_unlock_irq(&info->lock);
if (actually_throttled)
rx_data_softint(&info->rx_work);
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index e20dc525d177..589f6b4404f0 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -696,7 +696,7 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* device supports and needs bigger sense buffer */
if (us->fflags & US_FL_SANE_SENSE)
sense_size = ~0;
-
+Retry_Sense:
US_DEBUGP("Issuing auto-REQUEST_SENSE\n");
scsi_eh_prep_cmnd(srb, &ses, NULL, 0, sense_size);
@@ -720,6 +720,21 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
srb->result = DID_ABORT << 16;
goto Handle_Errors;
}
+
+ /* Some devices claim to support larger sense but fail when
+ * trying to request it. When a transport failure happens
+ * using US_FS_SANE_SENSE, we always retry with a standard
+ * (small) sense request. This fixes some USB GSM modems
+ */
+ if (temp_result == USB_STOR_TRANSPORT_FAILED &&
+ (us->fflags & US_FL_SANE_SENSE) &&
+ sense_size != US_SENSE_SIZE) {
+ US_DEBUGP("-- auto-sense failure, retry small sense\n");
+ sense_size = US_SENSE_SIZE;
+ goto Retry_Sense;
+ }
+
+ /* Other failures */
if (temp_result != USB_STOR_TRANSPORT_GOOD) {
US_DEBUGP("-- auto-sense failure\n");
@@ -768,17 +783,32 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
/* set the result so the higher layers expect this data */
srb->result = SAM_STAT_CHECK_CONDITION;
- /* If things are really okay, then let's show that. Zero
- * out the sense buffer so the higher layers won't realize
- * we did an unsolicited auto-sense. */
- if (result == USB_STOR_TRANSPORT_GOOD &&
- /* Filemark 0, ignore EOM, ILI 0, no sense */
+ /* We often get empty sense data. This could indicate that
+ * everything worked or that there was an unspecified
+ * problem. We have to decide which.
+ */
+ if ( /* Filemark 0, ignore EOM, ILI 0, no sense */
(srb->sense_buffer[2] & 0xaf) == 0 &&
/* No ASC or ASCQ */
srb->sense_buffer[12] == 0 &&
srb->sense_buffer[13] == 0) {
- srb->result = SAM_STAT_GOOD;
- srb->sense_buffer[0] = 0x0;
+
+ /* If things are really okay, then let's show that.
+ * Zero out the sense buffer so the higher layers
+ * won't realize we did an unsolicited auto-sense.
+ */
+ if (result == USB_STOR_TRANSPORT_GOOD) {
+ srb->result = SAM_STAT_GOOD;
+ srb->sense_buffer[0] = 0x0;
+
+ /* If there was a problem, report an unspecified
+ * hardware error to prevent the higher layers from
+ * entering an infinite retry loop.
+ */
+ } else {
+ srb->result = DID_ERROR << 16;
+ srb->sense_buffer[2] = HARDWARE_ERROR;
+ }
}
}
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 079ae0f7bec1..d4f034ebaa8a 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -1823,6 +1823,13 @@ UNUSUAL_DEV( 0x4102, 0x1020, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE ),
+/* Reported by Sergey Pinaev <dfo@antex.ru> */
+UNUSUAL_DEV( 0x4102, 0x1059, 0x0000, 0x0000,
+ "iRiver",
+ "P7K",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
/*
* David Härdeman <david@2gen.com>
* The key makes the SCSI stack print confusing (but harmless) messages
diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c
index b2f149fedcc5..4516c36436e6 100644
--- a/drivers/usb/wusbcore/security.c
+++ b/drivers/usb/wusbcore/security.c
@@ -200,35 +200,40 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,
{
int result, bytes, secd_size;
struct device *dev = &usb_dev->dev;
- struct usb_security_descriptor secd;
+ struct usb_security_descriptor *secd;
const struct usb_encryption_descriptor *etd, *ccm1_etd = NULL;
- void *secd_buf;
const void *itr, *top;
char buf[64];
+ secd = kmalloc(sizeof(struct usb_security_descriptor), GFP_KERNEL);
+ if (secd == NULL) {
+ result = -ENOMEM;
+ goto out;
+ }
+
result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
- 0, &secd, sizeof(secd));
+ 0, secd, sizeof(struct usb_security_descriptor));
if (result < sizeof(secd)) {
dev_err(dev, "Can't read security descriptor or "
"not enough data: %d\n", result);
- goto error_secd;
+ goto out;
}
- secd_size = le16_to_cpu(secd.wTotalLength);
- secd_buf = kmalloc(secd_size, GFP_KERNEL);
- if (secd_buf == NULL) {
+ secd_size = le16_to_cpu(secd->wTotalLength);
+ secd = krealloc(secd, secd_size, GFP_KERNEL);
+ if (secd == NULL) {
dev_err(dev, "Can't allocate space for security descriptors\n");
- goto error_secd_alloc;
+ goto out;
}
result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
- 0, secd_buf, secd_size);
+ 0, secd, secd_size);
if (result < secd_size) {
dev_err(dev, "Can't read security descriptor or "
"not enough data: %d\n", result);
- goto error_secd_all;
+ goto out;
}
bytes = 0;
- itr = secd_buf + sizeof(secd);
- top = secd_buf + result;
+ itr = &secd[1];
+ top = (void *)secd + result;
while (itr < top) {
etd = itr;
if (top - itr < sizeof(*etd)) {
@@ -259,24 +264,16 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,
dev_err(dev, "WUSB device doesn't support CCM1 encryption, "
"can't use!\n");
result = -EINVAL;
- goto error_no_ccm1;
+ goto out;
}
wusb_dev->ccm1_etd = *ccm1_etd;
dev_dbg(dev, "supported encryption: %s; using %s (0x%02x/%02x)\n",
buf, wusb_et_name(ccm1_etd->bEncryptionType),
ccm1_etd->bEncryptionValue, ccm1_etd->bAuthKeyIndex);
result = 0;
- kfree(secd_buf);
out:
+ kfree(secd);
return result;
-
-
-error_no_ccm1:
-error_secd_all:
- kfree(secd_buf);
-error_secd_alloc:
-error_secd:
- goto out;
}
void wusb_dev_sec_rm(struct wusb_dev *wusb_dev)
diff --git a/drivers/uwb/whc-rc.c b/drivers/uwb/whc-rc.c
index 1d9a6f54658e..01950c62dc8d 100644
--- a/drivers/uwb/whc-rc.c
+++ b/drivers/uwb/whc-rc.c
@@ -42,6 +42,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/sched.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
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/da8xx-fb.c b/drivers/video/da8xx-fb.c
index 42e1005e2916..d065894ce38f 100644
--- a/drivers/video/da8xx-fb.c
+++ b/drivers/video/da8xx-fb.c
@@ -26,7 +26,6 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
-#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <video/da8xx-fb.h>
diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c
index f2de5a1acd6d..5c5a1ad1d397 100644
--- a/drivers/video/msm/mddi.c
+++ b/drivers/video/msm/mddi.c
@@ -27,8 +27,6 @@
#include <mach/msm_iomap.h>
#include <mach/irqs.h>
#include <mach/board.h>
-#include <linux/delay.h>
-
#include <mach/msm_fb.h>
#include "mddi_hw.h"
diff --git a/drivers/video/omap/blizzard.c b/drivers/video/omap/blizzard.c
index d5e59556f9e2..70dadf9d2334 100644
--- a/drivers/video/omap/blizzard.c
+++ b/drivers/video/omap/blizzard.c
@@ -93,7 +93,7 @@ struct blizzard_reg_list {
};
/* These need to be saved / restored separately from the rest. */
-static struct blizzard_reg_list blizzard_pll_regs[] = {
+static const struct blizzard_reg_list blizzard_pll_regs[] = {
{
.start = 0x04, /* Don't save PLL ctrl (0x0C) */
.end = 0x0a,
@@ -104,7 +104,7 @@ static struct blizzard_reg_list blizzard_pll_regs[] = {
},
};
-static struct blizzard_reg_list blizzard_gen_regs[] = {
+static const struct blizzard_reg_list blizzard_gen_regs[] = {
{
.start = 0x18, /* SDRAM control */
.end = 0x20,
@@ -191,7 +191,7 @@ struct blizzard_struct {
struct omapfb_device *fbdev;
struct lcd_ctrl_extif *extif;
- struct lcd_ctrl *int_ctrl;
+ const struct lcd_ctrl *int_ctrl;
void (*power_up)(struct device *dev);
void (*power_down)(struct device *dev);
@@ -1372,7 +1372,7 @@ static void blizzard_get_caps(int plane, struct omapfb_caps *caps)
(1 << OMAPFB_COLOR_YUV420);
}
-static void _save_regs(struct blizzard_reg_list *list, int cnt)
+static void _save_regs(const struct blizzard_reg_list *list, int cnt)
{
int i;
@@ -1383,7 +1383,7 @@ static void _save_regs(struct blizzard_reg_list *list, int cnt)
}
}
-static void _restore_regs(struct blizzard_reg_list *list, int cnt)
+static void _restore_regs(const struct blizzard_reg_list *list, int cnt)
{
int i;
diff --git a/drivers/video/omap/omapfb_main.c b/drivers/video/omap/omapfb_main.c
index 125e605b8c68..0d0c8c8b9b56 100644
--- a/drivers/video/omap/omapfb_main.c
+++ b/drivers/video/omap/omapfb_main.c
@@ -393,7 +393,7 @@ static void omapfb_sync(struct fb_info *fbi)
* Set fb_info.fix fields and also updates fbdev.
* When calling this fb_info.var must be set up already.
*/
-static void set_fb_fix(struct fb_info *fbi)
+static void set_fb_fix(struct fb_info *fbi, int from_init)
{
struct fb_fix_screeninfo *fix = &fbi->fix;
struct fb_var_screeninfo *var = &fbi->var;
@@ -403,10 +403,16 @@ static void set_fb_fix(struct fb_info *fbi)
rg = &plane->fbdev->mem_desc.region[plane->idx];
fbi->screen_base = rg->vaddr;
- mutex_lock(&fbi->mm_lock);
- fix->smem_start = rg->paddr;
- fix->smem_len = rg->size;
- mutex_unlock(&fbi->mm_lock);
+
+ if (!from_init) {
+ mutex_lock(&fbi->mm_lock);
+ fix->smem_start = rg->paddr;
+ fix->smem_len = rg->size;
+ mutex_unlock(&fbi->mm_lock);
+ } else {
+ fix->smem_start = rg->paddr;
+ fix->smem_len = rg->size;
+ }
fix->type = FB_TYPE_PACKED_PIXELS;
bpp = var->bits_per_pixel;
@@ -704,7 +710,7 @@ static int omapfb_set_par(struct fb_info *fbi)
int r = 0;
omapfb_rqueue_lock(fbdev);
- set_fb_fix(fbi);
+ set_fb_fix(fbi, 0);
r = ctrl_change_mode(fbi);
omapfb_rqueue_unlock(fbdev);
@@ -904,7 +910,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi)
if (old_size != size) {
if (size) {
memcpy(&fbi->var, new_var, sizeof(fbi->var));
- set_fb_fix(fbi);
+ set_fb_fix(fbi, 0);
} else {
/*
* Set these explicitly to indicate that the
@@ -1504,7 +1510,7 @@ static int fbinfo_init(struct omapfb_device *fbdev, struct fb_info *info)
var->bits_per_pixel = fbdev->panel->bpp;
set_fb_var(info, var);
- set_fb_fix(info);
+ set_fb_fix(info, 1);
r = fb_alloc_cmap(&info->cmap, 16, 0);
if (r != 0)
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/watchdog/riowd.c b/drivers/watchdog/riowd.c
index 1e8f02f440e6..d3c824dc2358 100644
--- a/drivers/watchdog/riowd.c
+++ b/drivers/watchdog/riowd.c
@@ -206,7 +206,7 @@ static int __devinit riowd_probe(struct of_device *op,
dev_set_drvdata(&op->dev, p);
riowd_device = p;
- err = 0;
+ return 0;
out_iounmap:
of_iounmap(&op->resource[0], p->regs, 2);
diff --git a/firmware/Makefile b/firmware/Makefile
index 5ea80b19785b..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 \
@@ -67,10 +67,13 @@ fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin
fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \
e100/d102e_ucode.bin
fw-shipped-$(CONFIG_MYRI_SBUS) += myricom/lanai.bin
-fw-shipped-$(CONFIG_PCMCIA_PCNET) += cis/LA-PCM.cis cis/PCMLM28.cis
+fw-shipped-$(CONFIG_PCMCIA_PCNET) += cis/LA-PCM.cis cis/PCMLM28.cis \
+ cis/DP83903.cis cis/NE2K.cis \
+ cis/tamarack.cis
fw-shipped-$(CONFIG_PCMCIA_3C589) += cis/3CXEM556.cis
fw-shipped-$(CONFIG_PCMCIA_3C574) += cis/3CCFEM556.cis
-fw-shipped-$(CONFIG_SERIAL_8250_CS) += cis/MT5634ZLX.cis cis/RS-COM-2P.cis
+fw-shipped-$(CONFIG_SERIAL_8250_CS) += cis/MT5634ZLX.cis cis/RS-COM-2P.cis \
+ cis/COMpad2.cis cis/COMpad4.cis
fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin
fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \
advansys/3550.bin advansys/38C0800.bin
diff --git a/firmware/WHENCE b/firmware/WHENCE
index 3f8c4f6bc43f..a07aede9fcc3 100644
--- a/firmware/WHENCE
+++ b/firmware/WHENCE
@@ -597,6 +597,9 @@ Driver: PCMCIA_PCNET - NE2000 compatible PCMCIA adapter
File: cis/LA-PCM.cis
cis/PCMLM28.cis
+ cis/DP83903.cis
+ cis/NE2K.cis
+ cis/tamarack.cis
Licence: GPL
@@ -628,6 +631,8 @@ Driver: SERIAL_8250_CS - Serial PCMCIA adapter
File: cis/MT5634ZLX.cis
cis/RS-COM-2P.cis
+ cis/COMpad2.cis
+ cis/COMpad4.cis
Licence: GPL
@@ -669,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/firmware/cis/COMpad2.cis.ihex b/firmware/cis/COMpad2.cis.ihex
new file mode 100644
index 000000000000..1671c5e48caa
--- /dev/null
+++ b/firmware/cis/COMpad2.cis.ihex
@@ -0,0 +1,11 @@
+:1000000001030000FF151F0401414456414E5445B1
+:10001000434800434F4D7061642D33322F38350013
+:10002000312E300000FF210202011A0501050001F6
+:10003000031B0EC18118AA61E80207E8030730B864
+:100040009E1B08820108AA6030030F1B0883010869
+:10005000AA6040030F1B08840108AA6050030F1B0D
+:0D00600008850108AA6060030F1400FF006E
+:00000001FF
+#
+# Replacement CIS for Advantech COMpad-32/85
+#
diff --git a/firmware/cis/COMpad4.cis.ihex b/firmware/cis/COMpad4.cis.ihex
new file mode 100644
index 000000000000..27bbec1921b3
--- /dev/null
+++ b/firmware/cis/COMpad4.cis.ihex
@@ -0,0 +1,9 @@
+:1000000001030000FF151F0401414456414E5445B1
+:10001000434800434F4D7061642D33322F383542D1
+:100020002D34000000FF210202011A050102000127
+:10003000011B0BC18118AA6040021F30B89E1B082B
+:0C004000820108AA6040031F1400FF00AA
+:00000001FF
+#
+# Replacement CIS for Advantech COMpad-32/85B-4
+#
diff --git a/firmware/cis/DP83903.cis.ihex b/firmware/cis/DP83903.cis.ihex
new file mode 100644
index 000000000000..6d73ea3cf1b8
--- /dev/null
+++ b/firmware/cis/DP83903.cis.ihex
@@ -0,0 +1,14 @@
+:1000000001030000FF152904014D756C74696675C4
+:100010006E6374696F6E20436172640000004E531A
+:1000200043204D46204C414E2F4D6F64656D00FFBF
+:1000300020047501000021020000060B02004900A7
+:100040000000006A000000FF00130343495321022F
+:1000500006001A060517201077021B0C970179017C
+:10006000556530FFFF284000FF001303434953212B
+:100070000202001A060507401077021B09870119C2
+:0800800001552330FFFFFF00D2
+:00000001FF
+#
+# This CIS is for cards based on the National Semiconductor
+# DP83903 Multiple Function Interface Chip
+#
diff --git a/firmware/cis/NE2K.cis.ihex b/firmware/cis/NE2K.cis.ihex
new file mode 100644
index 000000000000..1bb40fc4759f
--- /dev/null
+++ b/firmware/cis/NE2K.cis.ihex
@@ -0,0 +1,8 @@
+:1000000001030000FF1515040150434D4349410011
+:1000100045746865726E6574000000FF2102060079
+:100020001A050120F803031B09E001190155653089
+:06003000FFFF1400FF00B9
+:00000001FF
+#
+# Replacement CIS for various busted NE2000-compatible cards
+#
diff --git a/firmware/cis/tamarack.cis.ihex b/firmware/cis/tamarack.cis.ihex
new file mode 100644
index 000000000000..1e86547fb361
--- /dev/null
+++ b/firmware/cis/tamarack.cis.ihex
@@ -0,0 +1,10 @@
+:100000000103D400FF17034100FF152404015441EC
+:100010004D415241434B0045746865726E657400F2
+:10002000410030303437343331313830303100FF33
+:10003000210206001A050120F803031B14E08119B0
+:100040003F554D5D06864626E551000F100F30FFE7
+:05005000FF1400FF0099
+:00000001FF
+#
+# Replacement CIS for Surecom, Tamarack NE2000 cards
+#
diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 69b355ae7f49..361604244271 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -27,7 +27,7 @@
#include "btrfs_inode.h"
#include "xattr.h"
-#ifdef CONFIG_BTRFS_POSIX_ACL
+#ifdef CONFIG_BTRFS_FS_POSIX_ACL
static struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
{
@@ -313,7 +313,7 @@ struct xattr_handler btrfs_xattr_acl_access_handler = {
.set = btrfs_xattr_acl_access_set,
};
-#else /* CONFIG_BTRFS_POSIX_ACL */
+#else /* CONFIG_BTRFS_FS_POSIX_ACL */
int btrfs_acl_chmod(struct inode *inode)
{
@@ -325,4 +325,4 @@ int btrfs_init_acl(struct inode *inode, struct inode *dir)
return 0;
}
-#endif /* CONFIG_BTRFS_POSIX_ACL */
+#endif /* CONFIG_BTRFS_FS_POSIX_ACL */
diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c
index 282ca085c2fb..c0861e781cdb 100644
--- a/fs/btrfs/async-thread.c
+++ b/fs/btrfs/async-thread.c
@@ -64,6 +64,51 @@ struct btrfs_worker_thread {
};
/*
+ * btrfs_start_workers uses kthread_run, which can block waiting for memory
+ * for a very long time. It will actually throttle on page writeback,
+ * and so it may not make progress until after our btrfs worker threads
+ * process all of the pending work structs in their queue
+ *
+ * This means we can't use btrfs_start_workers from inside a btrfs worker
+ * thread that is used as part of cleaning dirty memory, which pretty much
+ * involves all of the worker threads.
+ *
+ * Instead we have a helper queue who never has more than one thread
+ * where we scheduler thread start operations. This worker_start struct
+ * is used to contain the work and hold a pointer to the queue that needs
+ * another worker.
+ */
+struct worker_start {
+ struct btrfs_work work;
+ struct btrfs_workers *queue;
+};
+
+static void start_new_worker_func(struct btrfs_work *work)
+{
+ struct worker_start *start;
+ start = container_of(work, struct worker_start, work);
+ btrfs_start_workers(start->queue, 1);
+ kfree(start);
+}
+
+static int start_new_worker(struct btrfs_workers *queue)
+{
+ struct worker_start *start;
+ int ret;
+
+ start = kzalloc(sizeof(*start), GFP_NOFS);
+ if (!start)
+ return -ENOMEM;
+
+ start->work.func = start_new_worker_func;
+ start->queue = queue;
+ ret = btrfs_queue_worker(queue->atomic_worker_start, &start->work);
+ if (ret)
+ kfree(start);
+ return ret;
+}
+
+/*
* helper function to move a thread onto the idle list after it
* has finished some requests.
*/
@@ -118,11 +163,13 @@ static void check_pending_worker_creates(struct btrfs_worker_thread *worker)
goto out;
workers->atomic_start_pending = 0;
- if (workers->num_workers >= workers->max_workers)
+ if (workers->num_workers + workers->num_workers_starting >=
+ workers->max_workers)
goto out;
+ workers->num_workers_starting += 1;
spin_unlock_irqrestore(&workers->lock, flags);
- btrfs_start_workers(workers, 1);
+ start_new_worker(workers);
return;
out:
@@ -390,9 +437,11 @@ int btrfs_stop_workers(struct btrfs_workers *workers)
/*
* simple init on struct btrfs_workers
*/
-void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max)
+void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max,
+ struct btrfs_workers *async_helper)
{
workers->num_workers = 0;
+ workers->num_workers_starting = 0;
INIT_LIST_HEAD(&workers->worker_list);
INIT_LIST_HEAD(&workers->idle_list);
INIT_LIST_HEAD(&workers->order_list);
@@ -404,14 +453,15 @@ void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max)
workers->name = name;
workers->ordered = 0;
workers->atomic_start_pending = 0;
- workers->atomic_worker_start = 0;
+ workers->atomic_worker_start = async_helper;
}
/*
* starts new worker threads. This does not enforce the max worker
* count in case you need to temporarily go past it.
*/
-int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
+static int __btrfs_start_workers(struct btrfs_workers *workers,
+ int num_workers)
{
struct btrfs_worker_thread *worker;
int ret = 0;
@@ -444,6 +494,8 @@ int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
list_add_tail(&worker->worker_list, &workers->idle_list);
worker->idle = 1;
workers->num_workers++;
+ workers->num_workers_starting--;
+ WARN_ON(workers->num_workers_starting < 0);
spin_unlock_irq(&workers->lock);
}
return 0;
@@ -452,6 +504,14 @@ fail:
return ret;
}
+int btrfs_start_workers(struct btrfs_workers *workers, int num_workers)
+{
+ spin_lock_irq(&workers->lock);
+ workers->num_workers_starting += num_workers;
+ spin_unlock_irq(&workers->lock);
+ return __btrfs_start_workers(workers, num_workers);
+}
+
/*
* run through the list and find a worker thread that doesn't have a lot
* to do right now. This can return null if we aren't yet at the thread
@@ -461,7 +521,10 @@ static struct btrfs_worker_thread *next_worker(struct btrfs_workers *workers)
{
struct btrfs_worker_thread *worker;
struct list_head *next;
- int enforce_min = workers->num_workers < workers->max_workers;
+ int enforce_min;
+
+ enforce_min = (workers->num_workers + workers->num_workers_starting) <
+ workers->max_workers;
/*
* if we find an idle thread, don't move it to the end of the
@@ -509,15 +572,17 @@ again:
worker = next_worker(workers);
if (!worker) {
- if (workers->num_workers >= workers->max_workers) {
+ if (workers->num_workers + workers->num_workers_starting >=
+ workers->max_workers) {
goto fallback;
} else if (workers->atomic_worker_start) {
workers->atomic_start_pending = 1;
goto fallback;
} else {
+ workers->num_workers_starting++;
spin_unlock_irqrestore(&workers->lock, flags);
/* we're below the limit, start another worker */
- btrfs_start_workers(workers, 1);
+ __btrfs_start_workers(workers, 1);
goto again;
}
}
diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h
index fc089b95ec14..5077746cf85e 100644
--- a/fs/btrfs/async-thread.h
+++ b/fs/btrfs/async-thread.h
@@ -64,6 +64,8 @@ struct btrfs_workers {
/* current number of running workers */
int num_workers;
+ int num_workers_starting;
+
/* max number of workers allowed. changed by btrfs_start_workers */
int max_workers;
@@ -78,9 +80,10 @@ struct btrfs_workers {
/*
* are we allowed to sleep while starting workers or are we required
- * to start them at a later time?
+ * to start them at a later time? If we can't sleep, this indicates
+ * which queue we need to use to schedule thread creation.
*/
- int atomic_worker_start;
+ struct btrfs_workers *atomic_worker_start;
/* list with all the work threads. The workers on the idle thread
* may be actively servicing jobs, but they haven't yet hit the
@@ -109,7 +112,8 @@ struct btrfs_workers {
int btrfs_queue_worker(struct btrfs_workers *workers, struct btrfs_work *work);
int btrfs_start_workers(struct btrfs_workers *workers, int num_workers);
int btrfs_stop_workers(struct btrfs_workers *workers);
-void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max);
+void btrfs_init_workers(struct btrfs_workers *workers, char *name, int max,
+ struct btrfs_workers *async_starter);
int btrfs_requeue_work(struct btrfs_work *work);
void btrfs_set_work_high_prio(struct btrfs_work *work);
#endif
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index a54d354cefcb..f6783a42f010 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -86,6 +86,12 @@ struct btrfs_inode {
* transid of the trans_handle that last modified this inode
*/
u64 last_trans;
+
+ /*
+ * log transid when this inode was last modified
+ */
+ u64 last_sub_trans;
+
/*
* transid that last logged this inode
*/
@@ -128,12 +134,14 @@ struct btrfs_inode {
u64 last_unlink_trans;
/*
- * These two counters are for delalloc metadata reservations. We keep
- * track of how many extents we've accounted for vs how many extents we
- * have.
+ * Counters to keep track of the number of extent item's we may use due
+ * to delalloc and such. outstanding_extents is the number of extent
+ * items we think we'll end up using, and reserved_extents is the number
+ * of extent items we've reserved metadata for.
*/
- int delalloc_reserved_extents;
- int delalloc_extents;
+ spinlock_t accounting_lock;
+ int reserved_extents;
+ int outstanding_extents;
/*
* ordered_data_close is set by truncate when a file that used
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index dd8ced9814c4..444b3e9b92a4 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -691,14 +691,17 @@ struct btrfs_space_info {
struct list_head list;
+ /* for controlling how we free up space for allocations */
+ wait_queue_head_t allocate_wait;
+ wait_queue_head_t flush_wait;
+ int allocating_chunk;
+ int flushing;
+
/* for block groups in our same type */
struct list_head block_groups;
spinlock_t lock;
struct rw_semaphore groups_sem;
atomic_t caching_threads;
-
- int allocating_chunk;
- wait_queue_head_t wait;
};
/*
@@ -907,6 +910,7 @@ struct btrfs_fs_info {
* A third pool does submit_bio to avoid deadlocking with the other
* two
*/
+ struct btrfs_workers generic_worker;
struct btrfs_workers workers;
struct btrfs_workers delalloc_workers;
struct btrfs_workers endio_workers;
@@ -914,6 +918,7 @@ struct btrfs_fs_info {
struct btrfs_workers endio_meta_write_workers;
struct btrfs_workers endio_write_workers;
struct btrfs_workers submit_workers;
+ struct btrfs_workers enospc_workers;
/*
* fixup workers take dirty pages that didn't properly go through
* the cow mechanism and make them safe to write. It happens
@@ -1004,7 +1009,10 @@ struct btrfs_root {
atomic_t log_writers;
atomic_t log_commit[2];
unsigned long log_transid;
+ unsigned long last_log_commit;
unsigned long log_batch;
+ pid_t log_start_pid;
+ bool log_multiple_pids;
u64 objectid;
u64 last_trans;
@@ -1145,6 +1153,7 @@ struct btrfs_root {
#define BTRFS_MOUNT_FLUSHONCOMMIT (1 << 7)
#define BTRFS_MOUNT_SSD_SPREAD (1 << 8)
#define BTRFS_MOUNT_NOSSD (1 << 9)
+#define BTRFS_MOUNT_DISCARD (1 << 10)
#define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt)
#define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt)
@@ -2323,7 +2332,7 @@ int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode);
void btrfs_orphan_cleanup(struct btrfs_root *root);
int btrfs_cont_expand(struct inode *inode, loff_t size);
int btrfs_invalidate_inodes(struct btrfs_root *root);
-extern struct dentry_operations btrfs_dentry_operations;
+extern const struct dentry_operations btrfs_dentry_operations;
/* ioctl.c */
long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
@@ -2366,7 +2375,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options);
int btrfs_sync_fs(struct super_block *sb, int wait);
/* acl.c */
-#ifdef CONFIG_BTRFS_POSIX_ACL
+#ifdef CONFIG_BTRFS_FS_POSIX_ACL
int btrfs_check_acl(struct inode *inode, int mask);
#else
#define btrfs_check_acl NULL
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index af0435f79fa6..02b6afbd7450 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -917,6 +917,7 @@ static int __setup_root(u32 nodesize, u32 leafsize, u32 sectorsize,
atomic_set(&root->log_writers, 0);
root->log_batch = 0;
root->log_transid = 0;
+ root->last_log_commit = 0;
extent_io_tree_init(&root->dirty_log_pages,
fs_info->btree_inode->i_mapping, GFP_NOFS);
@@ -1087,6 +1088,7 @@ int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
WARN_ON(root->log_root);
root->log_root = log_root;
root->log_transid = 0;
+ root->last_log_commit = 0;
return 0;
}
@@ -1746,21 +1748,25 @@ struct btrfs_root *open_ctree(struct super_block *sb,
err = -EINVAL;
goto fail_iput;
}
-printk("thread pool is %d\n", fs_info->thread_pool_size);
- /*
- * we need to start all the end_io workers up front because the
- * queue work function gets called at interrupt time, and so it
- * cannot dynamically grow.
- */
+
+ btrfs_init_workers(&fs_info->generic_worker,
+ "genwork", 1, NULL);
+
btrfs_init_workers(&fs_info->workers, "worker",
- fs_info->thread_pool_size);
+ fs_info->thread_pool_size,
+ &fs_info->generic_worker);
btrfs_init_workers(&fs_info->delalloc_workers, "delalloc",
- fs_info->thread_pool_size);
+ fs_info->thread_pool_size,
+ &fs_info->generic_worker);
btrfs_init_workers(&fs_info->submit_workers, "submit",
min_t(u64, fs_devices->num_devices,
- fs_info->thread_pool_size));
+ fs_info->thread_pool_size),
+ &fs_info->generic_worker);
+ btrfs_init_workers(&fs_info->enospc_workers, "enospc",
+ fs_info->thread_pool_size,
+ &fs_info->generic_worker);
/* a higher idle thresh on the submit workers makes it much more
* likely that bios will be send down in a sane order to the
@@ -1774,15 +1780,20 @@ printk("thread pool is %d\n", fs_info->thread_pool_size);
fs_info->delalloc_workers.idle_thresh = 2;
fs_info->delalloc_workers.ordered = 1;
- btrfs_init_workers(&fs_info->fixup_workers, "fixup", 1);
+ btrfs_init_workers(&fs_info->fixup_workers, "fixup", 1,
+ &fs_info->generic_worker);
btrfs_init_workers(&fs_info->endio_workers, "endio",
- fs_info->thread_pool_size);
+ fs_info->thread_pool_size,
+ &fs_info->generic_worker);
btrfs_init_workers(&fs_info->endio_meta_workers, "endio-meta",
- fs_info->thread_pool_size);
+ fs_info->thread_pool_size,
+ &fs_info->generic_worker);
btrfs_init_workers(&fs_info->endio_meta_write_workers,
- "endio-meta-write", fs_info->thread_pool_size);
+ "endio-meta-write", fs_info->thread_pool_size,
+ &fs_info->generic_worker);
btrfs_init_workers(&fs_info->endio_write_workers, "endio-write",
- fs_info->thread_pool_size);
+ fs_info->thread_pool_size,
+ &fs_info->generic_worker);
/*
* endios are largely parallel and should have a very
@@ -1794,12 +1805,8 @@ printk("thread pool is %d\n", fs_info->thread_pool_size);
fs_info->endio_write_workers.idle_thresh = 2;
fs_info->endio_meta_write_workers.idle_thresh = 2;
- fs_info->endio_workers.atomic_worker_start = 1;
- fs_info->endio_meta_workers.atomic_worker_start = 1;
- fs_info->endio_write_workers.atomic_worker_start = 1;
- fs_info->endio_meta_write_workers.atomic_worker_start = 1;
-
btrfs_start_workers(&fs_info->workers, 1);
+ btrfs_start_workers(&fs_info->generic_worker, 1);
btrfs_start_workers(&fs_info->submit_workers, 1);
btrfs_start_workers(&fs_info->delalloc_workers, 1);
btrfs_start_workers(&fs_info->fixup_workers, 1);
@@ -1807,6 +1814,7 @@ printk("thread pool is %d\n", fs_info->thread_pool_size);
btrfs_start_workers(&fs_info->endio_meta_workers, 1);
btrfs_start_workers(&fs_info->endio_meta_write_workers, 1);
btrfs_start_workers(&fs_info->endio_write_workers, 1);
+ btrfs_start_workers(&fs_info->enospc_workers, 1);
fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super);
fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages,
@@ -2012,6 +2020,7 @@ fail_chunk_root:
free_extent_buffer(chunk_root->node);
free_extent_buffer(chunk_root->commit_root);
fail_sb_buffer:
+ btrfs_stop_workers(&fs_info->generic_worker);
btrfs_stop_workers(&fs_info->fixup_workers);
btrfs_stop_workers(&fs_info->delalloc_workers);
btrfs_stop_workers(&fs_info->workers);
@@ -2020,6 +2029,7 @@ fail_sb_buffer:
btrfs_stop_workers(&fs_info->endio_meta_write_workers);
btrfs_stop_workers(&fs_info->endio_write_workers);
btrfs_stop_workers(&fs_info->submit_workers);
+ btrfs_stop_workers(&fs_info->enospc_workers);
fail_iput:
invalidate_inode_pages2(fs_info->btree_inode->i_mapping);
iput(fs_info->btree_inode);
@@ -2437,6 +2447,7 @@ int close_ctree(struct btrfs_root *root)
iput(fs_info->btree_inode);
+ btrfs_stop_workers(&fs_info->generic_worker);
btrfs_stop_workers(&fs_info->fixup_workers);
btrfs_stop_workers(&fs_info->delalloc_workers);
btrfs_stop_workers(&fs_info->workers);
@@ -2445,6 +2456,7 @@ int close_ctree(struct btrfs_root *root)
btrfs_stop_workers(&fs_info->endio_meta_write_workers);
btrfs_stop_workers(&fs_info->endio_write_workers);
btrfs_stop_workers(&fs_info->submit_workers);
+ btrfs_stop_workers(&fs_info->enospc_workers);
btrfs_close_devices(fs_info->fs_devices);
btrfs_mapping_tree_free(&fs_info->mapping_tree);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 359a754c782c..e238a0cdac67 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1568,23 +1568,23 @@ static int remove_extent_backref(struct btrfs_trans_handle *trans,
return ret;
}
-#ifdef BIO_RW_DISCARD
static void btrfs_issue_discard(struct block_device *bdev,
u64 start, u64 len)
{
blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_KERNEL,
DISCARD_FL_BARRIER);
}
-#endif
static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
u64 num_bytes)
{
-#ifdef BIO_RW_DISCARD
int ret;
u64 map_length = num_bytes;
struct btrfs_multi_bio *multi = NULL;
+ if (!btrfs_test_opt(root, DISCARD))
+ return 0;
+
/* Tell the block device(s) that the sectors can be discarded */
ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
bytenr, &map_length, &multi, 0);
@@ -1604,9 +1604,6 @@ static int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr,
}
return ret;
-#else
- return 0;
-#endif
}
int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
@@ -2824,14 +2821,17 @@ int btrfs_unreserve_metadata_for_delalloc(struct btrfs_root *root,
num_items);
spin_lock(&meta_sinfo->lock);
- if (BTRFS_I(inode)->delalloc_reserved_extents <=
- BTRFS_I(inode)->delalloc_extents) {
+ spin_lock(&BTRFS_I(inode)->accounting_lock);
+ if (BTRFS_I(inode)->reserved_extents <=
+ BTRFS_I(inode)->outstanding_extents) {
+ spin_unlock(&BTRFS_I(inode)->accounting_lock);
spin_unlock(&meta_sinfo->lock);
return 0;
}
+ spin_unlock(&BTRFS_I(inode)->accounting_lock);
- BTRFS_I(inode)->delalloc_reserved_extents--;
- BUG_ON(BTRFS_I(inode)->delalloc_reserved_extents < 0);
+ BTRFS_I(inode)->reserved_extents--;
+ BUG_ON(BTRFS_I(inode)->reserved_extents < 0);
if (meta_sinfo->bytes_delalloc < num_bytes) {
bug = true;
@@ -2864,6 +2864,107 @@ static void check_force_delalloc(struct btrfs_space_info *meta_sinfo)
meta_sinfo->force_delalloc = 0;
}
+struct async_flush {
+ struct btrfs_root *root;
+ struct btrfs_space_info *info;
+ struct btrfs_work work;
+};
+
+static noinline void flush_delalloc_async(struct btrfs_work *work)
+{
+ struct async_flush *async;
+ struct btrfs_root *root;
+ struct btrfs_space_info *info;
+
+ async = container_of(work, struct async_flush, work);
+ root = async->root;
+ info = async->info;
+
+ btrfs_start_delalloc_inodes(root);
+ wake_up(&info->flush_wait);
+ btrfs_wait_ordered_extents(root, 0);
+
+ spin_lock(&info->lock);
+ info->flushing = 0;
+ spin_unlock(&info->lock);
+ wake_up(&info->flush_wait);
+
+ kfree(async);
+}
+
+static void wait_on_flush(struct btrfs_space_info *info)
+{
+ DEFINE_WAIT(wait);
+ u64 used;
+
+ while (1) {
+ prepare_to_wait(&info->flush_wait, &wait,
+ TASK_UNINTERRUPTIBLE);
+ spin_lock(&info->lock);
+ if (!info->flushing) {
+ spin_unlock(&info->lock);
+ break;
+ }
+
+ used = info->bytes_used + info->bytes_reserved +
+ info->bytes_pinned + info->bytes_readonly +
+ info->bytes_super + info->bytes_root +
+ info->bytes_may_use + info->bytes_delalloc;
+ if (used < info->total_bytes) {
+ spin_unlock(&info->lock);
+ break;
+ }
+ spin_unlock(&info->lock);
+ schedule();
+ }
+ finish_wait(&info->flush_wait, &wait);
+}
+
+static void flush_delalloc(struct btrfs_root *root,
+ struct btrfs_space_info *info)
+{
+ struct async_flush *async;
+ bool wait = false;
+
+ spin_lock(&info->lock);
+
+ if (!info->flushing) {
+ info->flushing = 1;
+ init_waitqueue_head(&info->flush_wait);
+ } else {
+ wait = true;
+ }
+
+ spin_unlock(&info->lock);
+
+ if (wait) {
+ wait_on_flush(info);
+ return;
+ }
+
+ async = kzalloc(sizeof(*async), GFP_NOFS);
+ if (!async)
+ goto flush;
+
+ async->root = root;
+ async->info = info;
+ async->work.func = flush_delalloc_async;
+
+ btrfs_queue_worker(&root->fs_info->enospc_workers,
+ &async->work);
+ wait_on_flush(info);
+ return;
+
+flush:
+ btrfs_start_delalloc_inodes(root);
+ btrfs_wait_ordered_extents(root, 0);
+
+ spin_lock(&info->lock);
+ info->flushing = 0;
+ spin_unlock(&info->lock);
+ wake_up(&info->flush_wait);
+}
+
static int maybe_allocate_chunk(struct btrfs_root *root,
struct btrfs_space_info *info)
{
@@ -2894,7 +2995,7 @@ static int maybe_allocate_chunk(struct btrfs_root *root,
if (!info->allocating_chunk) {
info->force_alloc = 1;
info->allocating_chunk = 1;
- init_waitqueue_head(&info->wait);
+ init_waitqueue_head(&info->allocate_wait);
} else {
wait = true;
}
@@ -2902,7 +3003,7 @@ static int maybe_allocate_chunk(struct btrfs_root *root,
spin_unlock(&info->lock);
if (wait) {
- wait_event(info->wait,
+ wait_event(info->allocate_wait,
!info->allocating_chunk);
return 1;
}
@@ -2923,7 +3024,7 @@ out:
spin_lock(&info->lock);
info->allocating_chunk = 0;
spin_unlock(&info->lock);
- wake_up(&info->wait);
+ wake_up(&info->allocate_wait);
if (ret)
return 0;
@@ -2981,21 +3082,20 @@ again:
filemap_flush(inode->i_mapping);
goto again;
} else if (flushed == 3) {
- btrfs_start_delalloc_inodes(root);
- btrfs_wait_ordered_extents(root, 0);
+ flush_delalloc(root, meta_sinfo);
goto again;
}
spin_lock(&meta_sinfo->lock);
meta_sinfo->bytes_delalloc -= num_bytes;
spin_unlock(&meta_sinfo->lock);
printk(KERN_ERR "enospc, has %d, reserved %d\n",
- BTRFS_I(inode)->delalloc_extents,
- BTRFS_I(inode)->delalloc_reserved_extents);
+ BTRFS_I(inode)->outstanding_extents,
+ BTRFS_I(inode)->reserved_extents);
dump_space_info(meta_sinfo, 0, 0);
return -ENOSPC;
}
- BTRFS_I(inode)->delalloc_reserved_extents++;
+ BTRFS_I(inode)->reserved_extents++;
check_force_delalloc(meta_sinfo);
spin_unlock(&meta_sinfo->lock);
@@ -3094,8 +3194,7 @@ again:
}
if (retries == 2) {
- btrfs_start_delalloc_inodes(root);
- btrfs_wait_ordered_extents(root, 0);
+ flush_delalloc(root, meta_sinfo);
goto again;
}
spin_lock(&meta_sinfo->lock);
@@ -3588,6 +3687,14 @@ static int pin_down_bytes(struct btrfs_trans_handle *trans,
if (is_data)
goto pinit;
+ /*
+ * discard is sloooow, and so triggering discards on
+ * individual btree blocks isn't a good plan. Just
+ * pin everything in discard mode.
+ */
+ if (btrfs_test_opt(root, DISCARD))
+ goto pinit;
+
buf = btrfs_find_tree_block(root, bytenr, num_bytes);
if (!buf)
goto pinit;
@@ -4029,6 +4136,7 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
int loop = 0;
bool found_uncached_bg = false;
bool failed_cluster_refill = false;
+ bool failed_alloc = false;
WARN_ON(num_bytes < root->sectorsize);
btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY);
@@ -4233,14 +4341,23 @@ refill_cluster:
offset = btrfs_find_space_for_alloc(block_group, search_start,
num_bytes, empty_size);
- if (!offset && (cached || (!cached &&
- loop == LOOP_CACHING_NOWAIT))) {
- goto loop;
- } else if (!offset && (!cached &&
- loop > LOOP_CACHING_NOWAIT)) {
+ /*
+ * If we didn't find a chunk, and we haven't failed on this
+ * block group before, and this block group is in the middle of
+ * caching and we are ok with waiting, then go ahead and wait
+ * for progress to be made, and set failed_alloc to true.
+ *
+ * If failed_alloc is true then we've already waited on this
+ * block group once and should move on to the next block group.
+ */
+ if (!offset && !failed_alloc && !cached &&
+ loop > LOOP_CACHING_NOWAIT) {
wait_block_group_cache_progress(block_group,
- num_bytes + empty_size);
+ num_bytes + empty_size);
+ failed_alloc = true;
goto have_block_group;
+ } else if (!offset) {
+ goto loop;
}
checks:
search_start = stripe_align(root, offset);
@@ -4288,6 +4405,7 @@ checks:
break;
loop:
failed_cluster_refill = false;
+ failed_alloc = false;
btrfs_put_block_group(block_group);
}
up_read(&space_info->groups_sem);
@@ -4799,6 +4917,7 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
u64 bytenr;
u64 generation;
u64 refs;
+ u64 flags;
u64 last = 0;
u32 nritems;
u32 blocksize;
@@ -4836,15 +4955,19 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
generation <= root->root_key.offset)
continue;
+ /* We don't lock the tree block, it's OK to be racy here */
+ ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
+ &refs, &flags);
+ BUG_ON(ret);
+ BUG_ON(refs == 0);
+
if (wc->stage == DROP_REFERENCE) {
- ret = btrfs_lookup_extent_info(trans, root,
- bytenr, blocksize,
- &refs, NULL);
- BUG_ON(ret);
- BUG_ON(refs == 0);
if (refs == 1)
goto reada;
+ if (wc->level == 1 &&
+ (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF))
+ continue;
if (!wc->update_ref ||
generation <= root->root_key.offset)
continue;
@@ -4853,6 +4976,10 @@ static noinline void reada_walk_down(struct btrfs_trans_handle *trans,
&wc->update_progress);
if (ret < 0)
continue;
+ } else {
+ if (wc->level == 1 &&
+ (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF))
+ continue;
}
reada:
ret = readahead_tree_block(root, bytenr, blocksize,
@@ -4876,7 +5003,7 @@ reada:
static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
- struct walk_control *wc)
+ struct walk_control *wc, int lookup_info)
{
int level = wc->level;
struct extent_buffer *eb = path->nodes[level];
@@ -4891,8 +5018,9 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
* when reference count of tree block is 1, it won't increase
* again. once full backref flag is set, we never clear it.
*/
- if ((wc->stage == DROP_REFERENCE && wc->refs[level] != 1) ||
- (wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag))) {
+ if (lookup_info &&
+ ((wc->stage == DROP_REFERENCE && wc->refs[level] != 1) ||
+ (wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag)))) {
BUG_ON(!path->locks[level]);
ret = btrfs_lookup_extent_info(trans, root,
eb->start, eb->len,
@@ -4953,7 +5081,7 @@ static noinline int walk_down_proc(struct btrfs_trans_handle *trans,
static noinline int do_walk_down(struct btrfs_trans_handle *trans,
struct btrfs_root *root,
struct btrfs_path *path,
- struct walk_control *wc)
+ struct walk_control *wc, int *lookup_info)
{
u64 bytenr;
u64 generation;
@@ -4973,8 +5101,10 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
* for the subtree
*/
if (wc->stage == UPDATE_BACKREF &&
- generation <= root->root_key.offset)
+ generation <= root->root_key.offset) {
+ *lookup_info = 1;
return 1;
+ }
bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]);
blocksize = btrfs_level_size(root, level - 1);
@@ -4987,14 +5117,19 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
btrfs_tree_lock(next);
btrfs_set_lock_blocking(next);
- if (wc->stage == DROP_REFERENCE) {
- ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
- &wc->refs[level - 1],
- &wc->flags[level - 1]);
- BUG_ON(ret);
- BUG_ON(wc->refs[level - 1] == 0);
+ ret = btrfs_lookup_extent_info(trans, root, bytenr, blocksize,
+ &wc->refs[level - 1],
+ &wc->flags[level - 1]);
+ BUG_ON(ret);
+ BUG_ON(wc->refs[level - 1] == 0);
+ *lookup_info = 0;
+ if (wc->stage == DROP_REFERENCE) {
if (wc->refs[level - 1] > 1) {
+ if (level == 1 &&
+ (wc->flags[0] & BTRFS_BLOCK_FLAG_FULL_BACKREF))
+ goto skip;
+
if (!wc->update_ref ||
generation <= root->root_key.offset)
goto skip;
@@ -5008,12 +5143,17 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
wc->stage = UPDATE_BACKREF;
wc->shared_level = level - 1;
}
+ } else {
+ if (level == 1 &&
+ (wc->flags[0] & BTRFS_BLOCK_FLAG_FULL_BACKREF))
+ goto skip;
}
if (!btrfs_buffer_uptodate(next, generation)) {
btrfs_tree_unlock(next);
free_extent_buffer(next);
next = NULL;
+ *lookup_info = 1;
}
if (!next) {
@@ -5036,21 +5176,22 @@ static noinline int do_walk_down(struct btrfs_trans_handle *trans,
skip:
wc->refs[level - 1] = 0;
wc->flags[level - 1] = 0;
+ if (wc->stage == DROP_REFERENCE) {
+ if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
+ parent = path->nodes[level]->start;
+ } else {
+ BUG_ON(root->root_key.objectid !=
+ btrfs_header_owner(path->nodes[level]));
+ parent = 0;
+ }
- if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) {
- parent = path->nodes[level]->start;
- } else {
- BUG_ON(root->root_key.objectid !=
- btrfs_header_owner(path->nodes[level]));
- parent = 0;
+ ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
+ root->root_key.objectid, level - 1, 0);
+ BUG_ON(ret);
}
-
- ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent,
- root->root_key.objectid, level - 1, 0);
- BUG_ON(ret);
-
btrfs_tree_unlock(next);
free_extent_buffer(next);
+ *lookup_info = 1;
return 1;
}
@@ -5164,6 +5305,7 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
struct walk_control *wc)
{
int level = wc->level;
+ int lookup_info = 1;
int ret;
while (level >= 0) {
@@ -5171,14 +5313,14 @@ static noinline int walk_down_tree(struct btrfs_trans_handle *trans,
btrfs_header_nritems(path->nodes[level]))
break;
- ret = walk_down_proc(trans, root, path, wc);
+ ret = walk_down_proc(trans, root, path, wc, lookup_info);
if (ret > 0)
break;
if (level == 0)
break;
- ret = do_walk_down(trans, root, path, wc);
+ ret = do_walk_down(trans, root, path, wc, &lookup_info);
if (ret > 0) {
path->slots[level]++;
continue;
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index de1793ba004a..96577e8bf9fd 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -460,7 +460,8 @@ static int clear_state_bit(struct extent_io_tree *tree,
struct extent_state *state, int bits, int wake,
int delete)
{
- int ret = state->state & bits;
+ int bits_to_clear = bits & ~EXTENT_DO_ACCOUNTING;
+ int ret = state->state & bits_to_clear;
if ((bits & EXTENT_DIRTY) && (state->state & EXTENT_DIRTY)) {
u64 range = state->end - state->start + 1;
@@ -468,7 +469,7 @@ static int clear_state_bit(struct extent_io_tree *tree,
tree->dirty_bytes -= range;
}
clear_state_cb(tree, state, bits);
- state->state &= ~bits;
+ state->state &= ~bits_to_clear;
if (wake)
wake_up(&state->wq);
if (delete || state->state == 0) {
@@ -956,7 +957,8 @@ int clear_extent_dirty(struct extent_io_tree *tree, u64 start, u64 end,
gfp_t mask)
{
return clear_extent_bit(tree, start, end,
- EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0,
+ EXTENT_DIRTY | EXTENT_DELALLOC |
+ EXTENT_DO_ACCOUNTING, 0, 0,
NULL, mask);
}
@@ -1401,12 +1403,7 @@ out_failed:
int extent_clear_unlock_delalloc(struct inode *inode,
struct extent_io_tree *tree,
u64 start, u64 end, struct page *locked_page,
- int unlock_pages,
- int clear_unlock,
- int clear_delalloc, int clear_dirty,
- int set_writeback,
- int end_writeback,
- int set_private2)
+ unsigned long op)
{
int ret;
struct page *pages[16];
@@ -1416,17 +1413,21 @@ int extent_clear_unlock_delalloc(struct inode *inode,
int i;
int clear_bits = 0;
- if (clear_unlock)
+ if (op & EXTENT_CLEAR_UNLOCK)
clear_bits |= EXTENT_LOCKED;
- if (clear_dirty)
+ if (op & EXTENT_CLEAR_DIRTY)
clear_bits |= EXTENT_DIRTY;
- if (clear_delalloc)
+ if (op & EXTENT_CLEAR_DELALLOC)
clear_bits |= EXTENT_DELALLOC;
+ if (op & EXTENT_CLEAR_ACCOUNTING)
+ clear_bits |= EXTENT_DO_ACCOUNTING;
+
clear_extent_bit(tree, start, end, clear_bits, 1, 0, NULL, GFP_NOFS);
- if (!(unlock_pages || clear_dirty || set_writeback || end_writeback ||
- set_private2))
+ if (!(op & (EXTENT_CLEAR_UNLOCK_PAGE | EXTENT_CLEAR_DIRTY |
+ EXTENT_SET_WRITEBACK | EXTENT_END_WRITEBACK |
+ EXTENT_SET_PRIVATE2)))
return 0;
while (nr_pages > 0) {
@@ -1435,20 +1436,20 @@ int extent_clear_unlock_delalloc(struct inode *inode,
nr_pages, ARRAY_SIZE(pages)), pages);
for (i = 0; i < ret; i++) {
- if (set_private2)
+ if (op & EXTENT_SET_PRIVATE2)
SetPagePrivate2(pages[i]);
if (pages[i] == locked_page) {
page_cache_release(pages[i]);
continue;
}
- if (clear_dirty)
+ if (op & EXTENT_CLEAR_DIRTY)
clear_page_dirty_for_io(pages[i]);
- if (set_writeback)
+ if (op & EXTENT_SET_WRITEBACK)
set_page_writeback(pages[i]);
- if (end_writeback)
+ if (op & EXTENT_END_WRITEBACK)
end_page_writeback(pages[i]);
- if (unlock_pages)
+ if (op & EXTENT_CLEAR_UNLOCK_PAGE)
unlock_page(pages[i]);
page_cache_release(pages[i]);
}
@@ -2714,7 +2715,8 @@ int extent_invalidatepage(struct extent_io_tree *tree,
lock_extent(tree, start, end, GFP_NOFS);
wait_on_page_writeback(page);
clear_extent_bit(tree, start, end,
- EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC,
+ EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
+ EXTENT_DO_ACCOUNTING,
1, 1, NULL, GFP_NOFS);
return 0;
}
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 4794ec891fed..36de250a7b2b 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -15,6 +15,7 @@
#define EXTENT_BUFFER_FILLED (1 << 8)
#define EXTENT_BOUNDARY (1 << 9)
#define EXTENT_NODATASUM (1 << 10)
+#define EXTENT_DO_ACCOUNTING (1 << 11)
#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK)
/* flags for bio submission */
@@ -25,6 +26,16 @@
#define EXTENT_BUFFER_BLOCKING 1
#define EXTENT_BUFFER_DIRTY 2
+/* these are flags for extent_clear_unlock_delalloc */
+#define EXTENT_CLEAR_UNLOCK_PAGE 0x1
+#define EXTENT_CLEAR_UNLOCK 0x2
+#define EXTENT_CLEAR_DELALLOC 0x4
+#define EXTENT_CLEAR_DIRTY 0x8
+#define EXTENT_SET_WRITEBACK 0x10
+#define EXTENT_END_WRITEBACK 0x20
+#define EXTENT_SET_PRIVATE2 0x40
+#define EXTENT_CLEAR_ACCOUNTING 0x80
+
/*
* page->private values. Every page that is controlled by the extent
* map has page->private set to one.
@@ -288,10 +299,5 @@ int extent_range_uptodate(struct extent_io_tree *tree,
int extent_clear_unlock_delalloc(struct inode *inode,
struct extent_io_tree *tree,
u64 start, u64 end, struct page *locked_page,
- int unlock_page,
- int clear_unlock,
- int clear_delalloc, int clear_dirty,
- int set_writeback,
- int end_writeback,
- int set_private2);
+ unsigned long op);
#endif
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index f19e1259a971..06550affbd27 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -878,7 +878,8 @@ again:
btrfs_put_ordered_extent(ordered);
clear_extent_bits(&BTRFS_I(inode)->io_tree, start_pos,
- last_pos - 1, EXTENT_DIRTY | EXTENT_DELALLOC,
+ last_pos - 1, EXTENT_DIRTY | EXTENT_DELALLOC |
+ EXTENT_DO_ACCOUNTING,
GFP_NOFS);
unlock_extent(&BTRFS_I(inode)->io_tree,
start_pos, last_pos - 1, GFP_NOFS);
@@ -1085,8 +1086,10 @@ out_nolock:
btrfs_end_transaction(trans, root);
else
btrfs_commit_transaction(trans, root);
- } else {
+ } else if (ret != BTRFS_NO_LOG_SYNC) {
btrfs_commit_transaction(trans, root);
+ } else {
+ btrfs_end_transaction(trans, root);
}
}
if (file->f_flags & O_DIRECT) {
@@ -1136,6 +1139,13 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
int ret = 0;
struct btrfs_trans_handle *trans;
+
+ /* we wait first, since the writeback may change the inode */
+ root->log_batch++;
+ /* the VFS called filemap_fdatawrite for us */
+ btrfs_wait_ordered_range(inode, 0, (u64)-1);
+ root->log_batch++;
+
/*
* check the transaction that last modified this inode
* and see if its already been committed
@@ -1143,6 +1153,11 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
if (!BTRFS_I(inode)->last_trans)
goto out;
+ /*
+ * if the last transaction that changed this file was before
+ * the current transaction, we can bail out now without any
+ * syncing
+ */
mutex_lock(&root->fs_info->trans_mutex);
if (BTRFS_I(inode)->last_trans <=
root->fs_info->last_trans_committed) {
@@ -1152,13 +1167,6 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
}
mutex_unlock(&root->fs_info->trans_mutex);
- root->log_batch++;
- filemap_fdatawrite(inode->i_mapping);
- btrfs_wait_ordered_range(inode, 0, (u64)-1);
- root->log_batch++;
-
- if (datasync && !(inode->i_state & I_DIRTY_PAGES))
- goto out;
/*
* ok we haven't committed the transaction yet, lets do a commit
*/
@@ -1187,14 +1195,18 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
*/
mutex_unlock(&dentry->d_inode->i_mutex);
- if (ret > 0) {
- ret = btrfs_commit_transaction(trans, root);
- } else {
- ret = btrfs_sync_log(trans, root);
- if (ret == 0)
- ret = btrfs_end_transaction(trans, root);
- else
+ if (ret != BTRFS_NO_LOG_SYNC) {
+ if (ret > 0) {
ret = btrfs_commit_transaction(trans, root);
+ } else {
+ ret = btrfs_sync_log(trans, root);
+ if (ret == 0)
+ ret = btrfs_end_transaction(trans, root);
+ else
+ ret = btrfs_commit_transaction(trans, root);
+ }
+ } else {
+ ret = btrfs_end_transaction(trans, root);
}
mutex_lock(&dentry->d_inode->i_mutex);
out:
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 112e5aa85892..dae12dc7e159 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -424,9 +424,12 @@ again:
* and free up our temp pages.
*/
extent_clear_unlock_delalloc(inode,
- &BTRFS_I(inode)->io_tree,
- start, end, NULL, 1, 0,
- 0, 1, 1, 1, 0);
+ &BTRFS_I(inode)->io_tree,
+ start, end, NULL,
+ EXTENT_CLEAR_UNLOCK_PAGE | EXTENT_CLEAR_DIRTY |
+ EXTENT_CLEAR_DELALLOC |
+ EXTENT_CLEAR_ACCOUNTING |
+ EXTENT_SET_WRITEBACK | EXTENT_END_WRITEBACK);
ret = 0;
goto free_pages_out;
}
@@ -637,11 +640,14 @@ static noinline int submit_compressed_extents(struct inode *inode,
* clear dirty, set writeback and unlock the pages.
*/
extent_clear_unlock_delalloc(inode,
- &BTRFS_I(inode)->io_tree,
- async_extent->start,
- async_extent->start +
- async_extent->ram_size - 1,
- NULL, 1, 1, 0, 1, 1, 0, 0);
+ &BTRFS_I(inode)->io_tree,
+ async_extent->start,
+ async_extent->start +
+ async_extent->ram_size - 1,
+ NULL, EXTENT_CLEAR_UNLOCK_PAGE |
+ EXTENT_CLEAR_UNLOCK |
+ EXTENT_CLEAR_DELALLOC |
+ EXTENT_CLEAR_DIRTY | EXTENT_SET_WRITEBACK);
ret = btrfs_submit_compressed_write(inode,
async_extent->start,
@@ -712,9 +718,15 @@ static noinline int cow_file_range(struct inode *inode,
start, end, 0, NULL);
if (ret == 0) {
extent_clear_unlock_delalloc(inode,
- &BTRFS_I(inode)->io_tree,
- start, end, NULL, 1, 1,
- 1, 1, 1, 1, 0);
+ &BTRFS_I(inode)->io_tree,
+ start, end, NULL,
+ EXTENT_CLEAR_UNLOCK_PAGE |
+ EXTENT_CLEAR_UNLOCK |
+ EXTENT_CLEAR_DELALLOC |
+ EXTENT_CLEAR_ACCOUNTING |
+ EXTENT_CLEAR_DIRTY |
+ EXTENT_SET_WRITEBACK |
+ EXTENT_END_WRITEBACK);
*nr_written = *nr_written +
(end - start + PAGE_CACHE_SIZE) / PAGE_CACHE_SIZE;
*page_started = 1;
@@ -738,6 +750,8 @@ static noinline int cow_file_range(struct inode *inode,
btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0);
while (disk_num_bytes > 0) {
+ unsigned long op;
+
cur_alloc_size = min(disk_num_bytes, root->fs_info->max_extent);
ret = btrfs_reserve_extent(trans, root, cur_alloc_size,
root->sectorsize, 0, alloc_hint,
@@ -789,10 +803,13 @@ static noinline int cow_file_range(struct inode *inode,
* Do set the Private2 bit so we know this page was properly
* setup for writepage
*/
+ op = unlock ? EXTENT_CLEAR_UNLOCK_PAGE : 0;
+ op |= EXTENT_CLEAR_UNLOCK | EXTENT_CLEAR_DELALLOC |
+ EXTENT_SET_PRIVATE2;
+
extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
start, start + ram_size - 1,
- locked_page, unlock, 1,
- 1, 0, 0, 0, 1);
+ locked_page, op);
disk_num_bytes -= cur_alloc_size;
num_bytes -= cur_alloc_size;
alloc_hint = ins.objectid + ins.offset;
@@ -864,8 +881,8 @@ static int cow_file_range_async(struct inode *inode, struct page *locked_page,
u64 cur_end;
int limit = 10 * 1024 * 1042;
- clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, EXTENT_LOCKED |
- EXTENT_DELALLOC, 1, 0, NULL, GFP_NOFS);
+ clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, EXTENT_LOCKED,
+ 1, 0, NULL, GFP_NOFS);
while (start < end) {
async_cow = kmalloc(sizeof(*async_cow), GFP_NOFS);
async_cow->inode = inode;
@@ -1006,6 +1023,7 @@ next_slot:
if (found_key.offset > cur_offset) {
extent_end = found_key.offset;
+ extent_type = 0;
goto out_check;
}
@@ -1112,8 +1130,10 @@ out_check:
BUG_ON(ret);
extent_clear_unlock_delalloc(inode, &BTRFS_I(inode)->io_tree,
- cur_offset, cur_offset + num_bytes - 1,
- locked_page, 1, 1, 1, 0, 0, 0, 1);
+ cur_offset, cur_offset + num_bytes - 1,
+ locked_page, EXTENT_CLEAR_UNLOCK_PAGE |
+ EXTENT_CLEAR_UNLOCK | EXTENT_CLEAR_DELALLOC |
+ EXTENT_SET_PRIVATE2);
cur_offset = extent_end;
if (cur_offset > end)
break;
@@ -1178,15 +1198,17 @@ static int btrfs_split_extent_hook(struct inode *inode,
root->fs_info->max_extent);
/*
- * if we break a large extent up then leave delalloc_extents be,
- * since we've already accounted for the large extent.
+ * if we break a large extent up then leave oustanding_extents
+ * be, since we've already accounted for the large extent.
*/
if (div64_u64(new_size + root->fs_info->max_extent - 1,
root->fs_info->max_extent) < num_extents)
return 0;
}
- BTRFS_I(inode)->delalloc_extents++;
+ spin_lock(&BTRFS_I(inode)->accounting_lock);
+ BTRFS_I(inode)->outstanding_extents++;
+ spin_unlock(&BTRFS_I(inode)->accounting_lock);
return 0;
}
@@ -1217,7 +1239,9 @@ static int btrfs_merge_extent_hook(struct inode *inode,
/* we're not bigger than the max, unreserve the space and go */
if (new_size <= root->fs_info->max_extent) {
- BTRFS_I(inode)->delalloc_extents--;
+ spin_lock(&BTRFS_I(inode)->accounting_lock);
+ BTRFS_I(inode)->outstanding_extents--;
+ spin_unlock(&BTRFS_I(inode)->accounting_lock);
return 0;
}
@@ -1231,7 +1255,9 @@ static int btrfs_merge_extent_hook(struct inode *inode,
root->fs_info->max_extent) > num_extents)
return 0;
- BTRFS_I(inode)->delalloc_extents--;
+ spin_lock(&BTRFS_I(inode)->accounting_lock);
+ BTRFS_I(inode)->outstanding_extents--;
+ spin_unlock(&BTRFS_I(inode)->accounting_lock);
return 0;
}
@@ -1253,7 +1279,9 @@ static int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end,
if (!(old & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
struct btrfs_root *root = BTRFS_I(inode)->root;
- BTRFS_I(inode)->delalloc_extents++;
+ spin_lock(&BTRFS_I(inode)->accounting_lock);
+ BTRFS_I(inode)->outstanding_extents++;
+ spin_unlock(&BTRFS_I(inode)->accounting_lock);
btrfs_delalloc_reserve_space(root, inode, end - start + 1);
spin_lock(&root->fs_info->delalloc_lock);
BTRFS_I(inode)->delalloc_bytes += end - start + 1;
@@ -1281,8 +1309,12 @@ static int btrfs_clear_bit_hook(struct inode *inode,
if ((state->state & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
struct btrfs_root *root = BTRFS_I(inode)->root;
- BTRFS_I(inode)->delalloc_extents--;
- btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
+ if (bits & EXTENT_DO_ACCOUNTING) {
+ spin_lock(&BTRFS_I(inode)->accounting_lock);
+ BTRFS_I(inode)->outstanding_extents--;
+ spin_unlock(&BTRFS_I(inode)->accounting_lock);
+ btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
+ }
spin_lock(&root->fs_info->delalloc_lock);
if (state->end - state->start + 1 >
@@ -3000,12 +3032,22 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
if ((offset & (blocksize - 1)) == 0)
goto out;
+ ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE);
+ if (ret)
+ goto out;
+
+ ret = btrfs_reserve_metadata_for_delalloc(root, inode, 1);
+ if (ret)
+ goto out;
ret = -ENOMEM;
again:
page = grab_cache_page(mapping, index);
- if (!page)
+ if (!page) {
+ btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
+ btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
goto out;
+ }
page_start = page_offset(page);
page_end = page_start + PAGE_CACHE_SIZE - 1;
@@ -3038,6 +3080,10 @@ again:
goto again;
}
+ clear_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end,
+ EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING,
+ GFP_NOFS);
+
ret = btrfs_set_extent_delalloc(inode, page_start, page_end);
if (ret) {
unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
@@ -3056,6 +3102,9 @@ again:
unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
out_unlock:
+ if (ret)
+ btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
+ btrfs_unreserve_metadata_for_delalloc(root, inode, 1);
unlock_page(page);
page_cache_release(page);
out:
@@ -3079,7 +3128,9 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
if (size <= hole_start)
return 0;
- btrfs_truncate_page(inode->i_mapping, inode->i_size);
+ err = btrfs_truncate_page(inode->i_mapping, inode->i_size);
+ if (err)
+ return err;
while (1) {
struct btrfs_ordered_extent *ordered;
@@ -3448,6 +3499,7 @@ static noinline void init_btrfs_i(struct inode *inode)
bi->generation = 0;
bi->sequence = 0;
bi->last_trans = 0;
+ bi->last_sub_trans = 0;
bi->logged_trans = 0;
bi->delalloc_bytes = 0;
bi->reserved_bytes = 0;
@@ -3598,12 +3650,14 @@ static int btrfs_dentry_delete(struct dentry *dentry)
{
struct btrfs_root *root;
- if (!dentry->d_inode)
- return 0;
+ if (!dentry->d_inode && !IS_ROOT(dentry))
+ dentry = dentry->d_parent;
- root = BTRFS_I(dentry->d_inode)->root;
- if (btrfs_root_refs(&root->root_item) == 0)
- return 1;
+ if (dentry->d_inode) {
+ root = BTRFS_I(dentry->d_inode)->root;
+ if (btrfs_root_refs(&root->root_item) == 0)
+ return 1;
+ }
return 0;
}
@@ -4808,7 +4862,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
*/
clear_extent_bit(tree, page_start, page_end,
EXTENT_DIRTY | EXTENT_DELALLOC |
- EXTENT_LOCKED, 1, 0, NULL, GFP_NOFS);
+ EXTENT_LOCKED | EXTENT_DO_ACCOUNTING, 1, 0,
+ NULL, GFP_NOFS);
/*
* whoever cleared the private bit is responsible
* for the finish_ordered_io
@@ -4821,8 +4876,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned long offset)
lock_extent(tree, page_start, page_end, GFP_NOFS);
}
clear_extent_bit(tree, page_start, page_end,
- EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC,
- 1, 1, NULL, GFP_NOFS);
+ EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
+ EXTENT_DO_ACCOUNTING, 1, 1, NULL, GFP_NOFS);
__btrfs_releasepage(page, GFP_NOFS);
ClearPageChecked(page);
@@ -4917,7 +4972,8 @@ again:
* prepare_pages in the normal write path.
*/
clear_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end,
- EXTENT_DIRTY | EXTENT_DELALLOC, GFP_NOFS);
+ EXTENT_DIRTY | EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING,
+ GFP_NOFS);
ret = btrfs_set_extent_delalloc(inode, page_start, page_end);
if (ret) {
@@ -4944,7 +5000,9 @@ again:
set_page_dirty(page);
SetPageUptodate(page);
- BTRFS_I(inode)->last_trans = root->fs_info->generation + 1;
+ BTRFS_I(inode)->last_trans = root->fs_info->generation;
+ BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid;
+
unlock_extent(io_tree, page_start, page_end, GFP_NOFS);
out_unlock:
@@ -4969,7 +5027,9 @@ static void btrfs_truncate(struct inode *inode)
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return;
- btrfs_truncate_page(inode->i_mapping, inode->i_size);
+ ret = btrfs_truncate_page(inode->i_mapping, inode->i_size);
+ if (ret)
+ return;
btrfs_wait_ordered_range(inode, inode->i_size & (~mask), (u64)-1);
trans = btrfs_start_transaction(root, 1);
@@ -5064,9 +5124,11 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
if (!ei)
return NULL;
ei->last_trans = 0;
+ ei->last_sub_trans = 0;
ei->logged_trans = 0;
- ei->delalloc_extents = 0;
- ei->delalloc_reserved_extents = 0;
+ ei->outstanding_extents = 0;
+ ei->reserved_extents = 0;
+ spin_lock_init(&ei->accounting_lock);
btrfs_ordered_inode_tree_init(&ei->ordered_tree);
INIT_LIST_HEAD(&ei->i_orphan);
INIT_LIST_HEAD(&ei->ordered_operations);
@@ -5805,6 +5867,6 @@ static const struct inode_operations btrfs_symlink_inode_operations = {
.removexattr = btrfs_removexattr,
};
-struct dentry_operations btrfs_dentry_operations = {
+const struct dentry_operations btrfs_dentry_operations = {
.d_delete = btrfs_dentry_delete,
};
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 9a780c8d0ac8..cdbb054102b9 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -830,6 +830,7 @@ out_up_write:
out_unlock:
mutex_unlock(&inode->i_mutex);
if (!err) {
+ shrink_dcache_sb(root->fs_info->sb);
btrfs_invalidate_inodes(dest);
d_delete(dentry);
}
@@ -1122,8 +1123,10 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
datao += off - key.offset;
datal -= off - key.offset;
}
- if (key.offset + datao + datal > off + len)
- datal = off + len - key.offset - datao;
+
+ if (key.offset + datal > off + len)
+ datal = off + len - key.offset;
+
/* disko == 0 means it's a hole */
if (!disko)
datao = 0;
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 897fba835f89..5799bc46a309 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -306,6 +306,12 @@ int btrfs_remove_ordered_extent(struct inode *inode,
tree->last = NULL;
set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags);
+ spin_lock(&BTRFS_I(inode)->accounting_lock);
+ BTRFS_I(inode)->outstanding_extents--;
+ spin_unlock(&BTRFS_I(inode)->accounting_lock);
+ btrfs_unreserve_metadata_for_delalloc(BTRFS_I(inode)->root,
+ inode, 1);
+
spin_lock(&BTRFS_I(inode)->root->fs_info->ordered_extent_lock);
list_del_init(&entry->root_extent_list);
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index 361ad323faac..cfcc93c93a7b 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -3518,7 +3518,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
BUG_ON(!rc->block_group);
btrfs_init_workers(&rc->workers, "relocate",
- fs_info->thread_pool_size);
+ fs_info->thread_pool_size, NULL);
rc->extent_root = extent_root;
btrfs_prepare_block_group_relocation(extent_root, rc->block_group);
@@ -3701,7 +3701,7 @@ int btrfs_recover_relocation(struct btrfs_root *root)
mapping_tree_init(&rc->reloc_root_tree);
INIT_LIST_HEAD(&rc->reloc_roots);
btrfs_init_workers(&rc->workers, "relocate",
- root->fs_info->thread_pool_size);
+ root->fs_info->thread_pool_size, NULL);
rc->extent_root = root->fs_info->extent_root;
set_reloc_control(rc);
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 9de9b2236419..752a5463bf53 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -66,7 +66,8 @@ enum {
Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow,
Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
Opt_ssd, Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl,
- Opt_compress, Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_err,
+ Opt_compress, Opt_notreelog, Opt_ratio, Opt_flushoncommit,
+ Opt_discard, Opt_err,
};
static match_table_t tokens = {
@@ -88,6 +89,7 @@ static match_table_t tokens = {
{Opt_notreelog, "notreelog"},
{Opt_flushoncommit, "flushoncommit"},
{Opt_ratio, "metadata_ratio=%d"},
+ {Opt_discard, "discard"},
{Opt_err, NULL},
};
@@ -257,6 +259,9 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
info->metadata_ratio);
}
break;
+ case Opt_discard:
+ btrfs_set_opt(info->mount_opt, DISCARD);
+ break;
default:
break;
}
@@ -344,7 +349,7 @@ static int btrfs_fill_super(struct super_block *sb,
sb->s_export_op = &btrfs_export_ops;
sb->s_xattr = btrfs_xattr_handlers;
sb->s_time_gran = 1;
-#ifdef CONFIG_BTRFS_POSIX_ACL
+#ifdef CONFIG_BTRFS_FS_POSIX_ACL
sb->s_flags |= MS_POSIXACL;
#endif
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 0b8f36d4400a..bca82a4ca8e6 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -344,10 +344,10 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
/*
* when btree blocks are allocated, they have some corresponding bits set for
* them in one of two extent_io trees. This is used to make sure all of
- * those extents are on disk for transaction or log commit
+ * those extents are sent to disk but does not wait on them
*/
-int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
- struct extent_io_tree *dirty_pages)
+int btrfs_write_marked_extents(struct btrfs_root *root,
+ struct extent_io_tree *dirty_pages)
{
int ret;
int err = 0;
@@ -394,6 +394,29 @@ int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
page_cache_release(page);
}
}
+ if (err)
+ werr = err;
+ return werr;
+}
+
+/*
+ * when btree blocks are allocated, they have some corresponding bits set for
+ * them in one of two extent_io trees. This is used to make sure all of
+ * those extents are on disk for transaction or log commit. We wait
+ * on all the pages and clear them from the dirty pages state tree
+ */
+int btrfs_wait_marked_extents(struct btrfs_root *root,
+ struct extent_io_tree *dirty_pages)
+{
+ int ret;
+ int err = 0;
+ int werr = 0;
+ struct page *page;
+ struct inode *btree_inode = root->fs_info->btree_inode;
+ u64 start = 0;
+ u64 end;
+ unsigned long index;
+
while (1) {
ret = find_first_extent_bit(dirty_pages, 0, &start, &end,
EXTENT_DIRTY);
@@ -424,6 +447,22 @@ int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
return werr;
}
+/*
+ * when btree blocks are allocated, they have some corresponding bits set for
+ * them in one of two extent_io trees. This is used to make sure all of
+ * those extents are on disk for transaction or log commit
+ */
+int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
+ struct extent_io_tree *dirty_pages)
+{
+ int ret;
+ int ret2;
+
+ ret = btrfs_write_marked_extents(root, dirty_pages);
+ ret2 = btrfs_wait_marked_extents(root, dirty_pages);
+ return ret || ret2;
+}
+
int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans,
struct btrfs_root *root)
{
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index 663c67404918..d4e3e7a6938c 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -79,6 +79,7 @@ static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans,
struct inode *inode)
{
BTRFS_I(inode)->last_trans = trans->transaction->transid;
+ BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid;
}
int btrfs_end_transaction(struct btrfs_trans_handle *trans,
@@ -107,5 +108,9 @@ int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_write_and_wait_marked_extents(struct btrfs_root *root,
struct extent_io_tree *dirty_pages);
+int btrfs_write_marked_extents(struct btrfs_root *root,
+ struct extent_io_tree *dirty_pages);
+int btrfs_wait_marked_extents(struct btrfs_root *root,
+ struct extent_io_tree *dirty_pages);
int btrfs_transaction_in_commit(struct btrfs_fs_info *info);
#endif
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 7827841b55cb..741666a7676a 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -137,11 +137,20 @@ static int start_log_trans(struct btrfs_trans_handle *trans,
mutex_lock(&root->log_mutex);
if (root->log_root) {
+ if (!root->log_start_pid) {
+ root->log_start_pid = current->pid;
+ root->log_multiple_pids = false;
+ } else if (root->log_start_pid != current->pid) {
+ root->log_multiple_pids = true;
+ }
+
root->log_batch++;
atomic_inc(&root->log_writers);
mutex_unlock(&root->log_mutex);
return 0;
}
+ root->log_multiple_pids = false;
+ root->log_start_pid = current->pid;
mutex_lock(&root->fs_info->tree_log_mutex);
if (!root->fs_info->log_root_tree) {
ret = btrfs_init_log_root_tree(trans, root->fs_info);
@@ -1971,6 +1980,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
int ret;
struct btrfs_root *log = root->log_root;
struct btrfs_root *log_root_tree = root->fs_info->log_root_tree;
+ u64 log_transid = 0;
mutex_lock(&root->log_mutex);
index1 = root->log_transid % 2;
@@ -1987,10 +1997,11 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
while (1) {
unsigned long batch = root->log_batch;
- mutex_unlock(&root->log_mutex);
- schedule_timeout_uninterruptible(1);
- mutex_lock(&root->log_mutex);
-
+ if (root->log_multiple_pids) {
+ mutex_unlock(&root->log_mutex);
+ schedule_timeout_uninterruptible(1);
+ mutex_lock(&root->log_mutex);
+ }
wait_for_writer(trans, root);
if (batch == root->log_batch)
break;
@@ -2003,14 +2014,19 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
goto out;
}
- ret = btrfs_write_and_wait_marked_extents(log, &log->dirty_log_pages);
+ /* we start IO on all the marked extents here, but we don't actually
+ * wait for them until later.
+ */
+ ret = btrfs_write_marked_extents(log, &log->dirty_log_pages);
BUG_ON(ret);
btrfs_set_root_node(&log->root_item, log->node);
root->log_batch = 0;
+ log_transid = root->log_transid;
root->log_transid++;
log->log_transid = root->log_transid;
+ root->log_start_pid = 0;
smp_mb();
/*
* log tree has been flushed to disk, new modifications of
@@ -2036,6 +2052,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
index2 = log_root_tree->log_transid % 2;
if (atomic_read(&log_root_tree->log_commit[index2])) {
+ btrfs_wait_marked_extents(log, &log->dirty_log_pages);
wait_log_commit(trans, log_root_tree,
log_root_tree->log_transid);
mutex_unlock(&log_root_tree->log_mutex);
@@ -2055,6 +2072,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
* check the full commit flag again
*/
if (root->fs_info->last_trans_log_full_commit == trans->transid) {
+ btrfs_wait_marked_extents(log, &log->dirty_log_pages);
mutex_unlock(&log_root_tree->log_mutex);
ret = -EAGAIN;
goto out_wake_log_root;
@@ -2063,6 +2081,7 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
ret = btrfs_write_and_wait_marked_extents(log_root_tree,
&log_root_tree->dirty_log_pages);
BUG_ON(ret);
+ btrfs_wait_marked_extents(log, &log->dirty_log_pages);
btrfs_set_super_log_root(&root->fs_info->super_for_commit,
log_root_tree->node->start);
@@ -2082,9 +2101,14 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans,
* the running transaction open, so a full commit can't hop
* in and cause problems either.
*/
- write_ctree_super(trans, root->fs_info->tree_root, 2);
+ write_ctree_super(trans, root->fs_info->tree_root, 1);
ret = 0;
+ mutex_lock(&root->log_mutex);
+ if (root->last_log_commit < log_transid)
+ root->last_log_commit = log_transid;
+ mutex_unlock(&root->log_mutex);
+
out_wake_log_root:
atomic_set(&log_root_tree->log_commit[index2], 0);
smp_mb();
@@ -2852,6 +2876,21 @@ out:
return ret;
}
+static int inode_in_log(struct btrfs_trans_handle *trans,
+ struct inode *inode)
+{
+ struct btrfs_root *root = BTRFS_I(inode)->root;
+ int ret = 0;
+
+ mutex_lock(&root->log_mutex);
+ if (BTRFS_I(inode)->logged_trans == trans->transid &&
+ BTRFS_I(inode)->last_sub_trans <= root->last_log_commit)
+ ret = 1;
+ mutex_unlock(&root->log_mutex);
+ return ret;
+}
+
+
/*
* helper function around btrfs_log_inode to make sure newly created
* parent directories also end up in the log. A minimal inode and backref
@@ -2891,6 +2930,11 @@ int btrfs_log_inode_parent(struct btrfs_trans_handle *trans,
if (ret)
goto end_no_trans;
+ if (inode_in_log(trans, inode)) {
+ ret = BTRFS_NO_LOG_SYNC;
+ goto end_no_trans;
+ }
+
start_log_trans(trans, root);
ret = btrfs_log_inode(trans, root, inode, inode_only);
diff --git a/fs/btrfs/tree-log.h b/fs/btrfs/tree-log.h
index d09c7609e16b..0776eacb5083 100644
--- a/fs/btrfs/tree-log.h
+++ b/fs/btrfs/tree-log.h
@@ -19,6 +19,9 @@
#ifndef __TREE_LOG_
#define __TREE_LOG_
+/* return value for btrfs_log_dentry_safe that means we don't need to log it at all */
+#define BTRFS_NO_LOG_SYNC 256
+
int btrfs_sync_log(struct btrfs_trans_handle *trans,
struct btrfs_root *root);
int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root);
diff --git a/fs/btrfs/xattr.c b/fs/btrfs/xattr.c
index b0fc93f95fd0..b6dd5967c48a 100644
--- a/fs/btrfs/xattr.c
+++ b/fs/btrfs/xattr.c
@@ -260,7 +260,7 @@ err:
* attributes are handled directly.
*/
struct xattr_handler *btrfs_xattr_handlers[] = {
-#ifdef CONFIG_BTRFS_POSIX_ACL
+#ifdef CONFIG_BTRFS_FS_POSIX_ACL
&btrfs_xattr_acl_access_handler,
&btrfs_xattr_acl_default_handler,
#endif
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/dlm/lowcomms.c b/fs/dlm/lowcomms.c
index 240cef14fe58..70736eb4b516 100644
--- a/fs/dlm/lowcomms.c
+++ b/fs/dlm/lowcomms.c
@@ -316,6 +316,10 @@ int dlm_lowcomms_connect_node(int nodeid)
{
struct connection *con;
+ /* with sctp there's no connecting without sending */
+ if (dlm_config.ci_protocol != 0)
+ return 0;
+
if (nodeid == dlm_our_nodeid())
return 0;
@@ -455,9 +459,9 @@ static void process_sctp_notification(struct connection *con,
int prim_len, ret;
int addr_len;
struct connection *new_con;
- struct file *file;
sctp_peeloff_arg_t parg;
int parglen = sizeof(parg);
+ int err;
/*
* We get this before any data for an association.
@@ -512,19 +516,22 @@ static void process_sctp_notification(struct connection *con,
ret = kernel_getsockopt(con->sock, IPPROTO_SCTP,
SCTP_SOCKOPT_PEELOFF,
(void *)&parg, &parglen);
- if (ret) {
+ if (ret < 0) {
log_print("Can't peel off a socket for "
- "connection %d to node %d: err=%d\n",
+ "connection %d to node %d: err=%d",
parg.associd, nodeid, ret);
+ return;
+ }
+ new_con->sock = sockfd_lookup(parg.sd, &err);
+ if (!new_con->sock) {
+ log_print("sockfd_lookup error %d", err);
+ return;
}
- file = fget(parg.sd);
- new_con->sock = SOCKET_I(file->f_dentry->d_inode);
add_sock(new_con->sock, new_con);
- fput(file);
- put_unused_fd(parg.sd);
+ sockfd_put(new_con->sock);
- log_print("got new/restarted association %d nodeid %d",
- (int)sn->sn_assoc_change.sac_assoc_id, nodeid);
+ log_print("connecting to %d sctp association %d",
+ nodeid, (int)sn->sn_assoc_change.sac_assoc_id);
/* Send any pending writes */
clear_bit(CF_CONNECT_PENDING, &new_con->flags);
@@ -837,8 +844,6 @@ static void sctp_init_assoc(struct connection *con)
if (con->retries++ > MAX_CONNECT_RETRIES)
return;
- log_print("Initiating association with node %d", con->nodeid);
-
if (nodeid_to_addr(con->nodeid, (struct sockaddr *)&rem_addr)) {
log_print("no address for nodeid %d", con->nodeid);
return;
@@ -855,11 +860,14 @@ static void sctp_init_assoc(struct connection *con)
outmessage.msg_flags = MSG_EOR;
spin_lock(&con->writequeue_lock);
- e = list_entry(con->writequeue.next, struct writequeue_entry,
- list);
- BUG_ON((struct list_head *) e == &con->writequeue);
+ if (list_empty(&con->writequeue)) {
+ spin_unlock(&con->writequeue_lock);
+ log_print("writequeue empty for nodeid %d", con->nodeid);
+ return;
+ }
+ e = list_first_entry(&con->writequeue, struct writequeue_entry, list);
len = e->len;
offset = e->offset;
spin_unlock(&con->writequeue_lock);
diff --git a/fs/ecryptfs/Kconfig b/fs/ecryptfs/Kconfig
index 8aadb99b7634..1cd6d9d3e29a 100644
--- a/fs/ecryptfs/Kconfig
+++ b/fs/ecryptfs/Kconfig
@@ -1,8 +1,9 @@
config ECRYPT_FS
tristate "eCrypt filesystem layer support (EXPERIMENTAL)"
- depends on EXPERIMENTAL && KEYS && NET
+ depends on EXPERIMENTAL && KEYS && CRYPTO
select CRYPTO_ECB
select CRYPTO_CBC
+ select CRYPTO_MD5
help
Encrypted filesystem that operates on the VFS layer. See
<file:Documentation/filesystems/ecryptfs.txt> to learn more about
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 101fe4c7b1ee..c6ac85d6c701 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -35,6 +35,7 @@
#include <linux/key.h>
#include <linux/parser.h>
#include <linux/fs_stack.h>
+#include <linux/ima.h>
#include "ecryptfs_kernel.h"
/**
@@ -118,6 +119,7 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
const struct cred *cred = current_cred();
struct ecryptfs_inode_info *inode_info =
ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);
+ int opened_lower_file = 0;
int rc = 0;
mutex_lock(&inode_info->lower_file_mutex);
@@ -134,9 +136,12 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)
"for lower_dentry [0x%p] and lower_mnt [0x%p]; "
"rc = [%d]\n", lower_dentry, lower_mnt, rc);
inode_info->lower_file = NULL;
- }
+ } else
+ opened_lower_file = 1;
}
mutex_unlock(&inode_info->lower_file_mutex);
+ if (opened_lower_file)
+ ima_counts_get(inode_info->lower_file);
return rc;
}
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 72743d360509..7a520a862f49 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -2321,7 +2321,18 @@ static int ext3_commit_super(struct super_block *sb,
if (!sbh)
return error;
- es->s_wtime = cpu_to_le32(get_seconds());
+ /*
+ * If the file system is mounted read-only, don't update the
+ * superblock write time. This avoids updating the superblock
+ * write time when we are mounting the root file system
+ * read/only but we need to replay the journal; at that point,
+ * for people who are east of GMT and who make their clock
+ * tick in localtime for Windows bug-for-bug compatibility,
+ * the clock is set in the future, and this will cause e2fsck
+ * to complain and force a full file system check.
+ */
+ if (!(sb->s_flags & MS_RDONLY))
+ es->s_wtime = cpu_to_le32(get_seconds());
es->s_free_blocks_count = cpu_to_le32(ext3_count_free_blocks(sb));
es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb));
BUFFER_TRACE(sbh, "marking dirty");
diff --git a/fs/file.c b/fs/file.c
index f313314f996f..87e129030ab1 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -10,6 +10,7 @@
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/time.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/file.h>
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/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..6b3d6cb2b170 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
@@ -1114,7 +1115,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 +1126,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 +1139,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;
@@ -1243,18 +1236,125 @@ 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_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 +1374,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..1d4fc0413a3f 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 {
@@ -1377,3 +1391,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..025d15ba24c0 100644
--- a/fs/gfs2/quota.h
+++ b/fs/gfs2/quota.h
@@ -25,7 +25,7 @@ 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);
@@ -50,5 +50,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..e7b24d59d4ff 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -106,13 +106,13 @@ static const match_table_t tokens = {
/**
* 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 +157,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 +210,7 @@ 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;
@@ -219,7 +219,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 +227,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;
}
}
@@ -484,8 +484,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;
@@ -712,8 +713,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);
@@ -1062,7 +1063,7 @@ 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;
spin_unlock(&gt->gt_spin);
- error = gfs2_mount_args(sdp, &args, data);
+ error = gfs2_mount_args(&args, data);
if (error)
return error;
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/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/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/nfs/client.c b/fs/nfs/client.c
index 63976c0ccc25..99ea196f071f 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -1180,7 +1180,7 @@ static int nfs4_init_client(struct nfs_client *clp,
1, flags & NFS_MOUNT_NORESVPORT);
if (error < 0)
goto error;
- memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
+ strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
error = nfs_idmap_new(clp);
if (error < 0) {
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 2636c26d56fa..fa3408f20112 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -121,7 +121,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE);
if (IS_ERR(mnt_path))
- return mnt;
+ return ERR_CAST(mnt_path);
mountdata->mnt_path = mnt_path;
maxbuflen = mnt_path - 1 - page2;
@@ -132,15 +132,15 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
if (buf->len <= 0 || buf->len >= maxbuflen)
continue;
- mountdata->addr = (struct sockaddr *)&addr;
-
if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len))
continue;
- mountdata->addrlen = nfs_parse_server_name(buf->data,
- buf->len,
- mountdata->addr, mountdata->addrlen);
+
+ mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
+ (struct sockaddr *)&addr, sizeof(addr));
if (mountdata->addrlen == 0)
continue;
+
+ mountdata->addr = (struct sockaddr *)&addr;
rpc_set_port(mountdata->addr, NFS_PORT);
memcpy(page2, buf->data, buf->len);
diff --git a/fs/nfs/nfs4renewd.c b/fs/nfs/nfs4renewd.c
index e27c6cef18f2..0156c01c212c 100644
--- a/fs/nfs/nfs4renewd.c
+++ b/fs/nfs/nfs4renewd.c
@@ -127,12 +127,6 @@ nfs4_schedule_state_renewal(struct nfs_client *clp)
}
void
-nfs4_renewd_prepare_shutdown(struct nfs_server *server)
-{
- cancel_delayed_work(&server->nfs_client->cl_renewd);
-}
-
-void
nfs4_kill_renewd(struct nfs_client *clp)
{
cancel_delayed_work_sync(&clp->cl_renewd);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 29786d3b9326..a2c18acb8568 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -728,22 +728,24 @@ static void nfs_umount_begin(struct super_block *sb)
unlock_kernel();
}
-static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(int flags)
+static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(unsigned int version)
{
struct nfs_parsed_mount_data *data;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (data) {
- data->flags = flags;
data->rsize = NFS_MAX_FILE_IO_SIZE;
data->wsize = NFS_MAX_FILE_IO_SIZE;
data->acregmin = NFS_DEF_ACREGMIN;
data->acregmax = NFS_DEF_ACREGMAX;
data->acdirmin = NFS_DEF_ACDIRMIN;
data->acdirmax = NFS_DEF_ACDIRMAX;
+ data->mount_server.port = NFS_UNSPEC_PORT;
data->nfs_server.port = NFS_UNSPEC_PORT;
+ data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
data->auth_flavors[0] = RPC_AUTH_UNIX;
data->auth_flavor_len = 1;
+ data->version = version;
data->minorversion = 0;
}
return data;
@@ -776,15 +778,13 @@ static int nfs_verify_server_address(struct sockaddr *addr)
* Select between a default port value and a user-specified port value.
* If a zero value is set, then autobind will be used.
*/
-static void nfs_set_default_port(struct sockaddr *sap, const int parsed_port,
+static void nfs_set_port(struct sockaddr *sap, int *port,
const unsigned short default_port)
{
- unsigned short port = default_port;
+ if (*port == NFS_UNSPEC_PORT)
+ *port = default_port;
- if (parsed_port != NFS_UNSPEC_PORT)
- port = parsed_port;
-
- rpc_set_port(sap, port);
+ rpc_set_port(sap, *port);
}
/*
@@ -1475,7 +1475,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
args->mount_server.addrlen = args->nfs_server.addrlen;
}
request.salen = args->mount_server.addrlen;
- nfs_set_default_port(request.sap, args->mount_server.port, 0);
+ nfs_set_port(request.sap, &args->mount_server.port, 0);
/*
* Now ask the mount server to map our export path
@@ -1711,8 +1711,6 @@ static int nfs_validate_mount_data(void *options,
if (!(data->flags & NFS_MOUNT_TCP))
args->nfs_server.protocol = XPRT_TRANSPORT_UDP;
- else
- args->nfs_server.protocol = XPRT_TRANSPORT_TCP;
/* N.B. caller will free nfs_server.hostname in all cases */
args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
args->namlen = data->namlen;
@@ -1767,7 +1765,7 @@ static int nfs_validate_mount_data(void *options,
goto out_v4_not_compiled;
#endif
- nfs_set_default_port(sap, args->nfs_server.port, 0);
+ nfs_set_port(sap, &args->nfs_server.port, 0);
nfs_set_mount_transport_protocol(args);
@@ -1848,9 +1846,10 @@ nfs_compare_remount_data(struct nfs_server *nfss,
data->acdirmin != nfss->acdirmin / HZ ||
data->acdirmax != nfss->acdirmax / HZ ||
data->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) ||
+ data->nfs_server.port != nfss->port ||
data->nfs_server.addrlen != nfss->nfs_client->cl_addrlen ||
- memcmp(&data->nfs_server.address, &nfss->nfs_client->cl_addr,
- data->nfs_server.addrlen) != 0)
+ !rpc_cmp_addr((struct sockaddr *)&data->nfs_server.address,
+ (struct sockaddr *)&nfss->nfs_client->cl_addr))
return -EINVAL;
return 0;
@@ -1893,6 +1892,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
data->acdirmin = nfss->acdirmin / HZ;
data->acdirmax = nfss->acdirmax / HZ;
data->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ;
+ data->nfs_server.port = nfss->port;
data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr,
data->nfs_server.addrlen);
@@ -2106,7 +2106,7 @@ static int nfs_get_sb(struct file_system_type *fs_type,
};
int error = -ENOMEM;
- data = nfs_alloc_parsed_mount_data(NFS_MOUNT_VER3 | NFS_MOUNT_TCP);
+ data = nfs_alloc_parsed_mount_data(3);
mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL);
if (data == NULL || mntfh == NULL)
goto out_free_fh;
@@ -2331,7 +2331,7 @@ static int nfs4_validate_text_mount_data(void *options,
{
struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
- nfs_set_default_port(sap, args->nfs_server.port, NFS_PORT);
+ nfs_set_port(sap, &args->nfs_server.port, NFS_PORT);
nfs_validate_transport_protocol(args);
@@ -2376,7 +2376,6 @@ static int nfs4_validate_mount_data(void *options,
if (data == NULL)
goto out_no_data;
- args->version = 4;
switch (data->version) {
case 1:
if (data->host_addrlen > sizeof(args->nfs_server.address))
@@ -2660,7 +2659,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
struct nfs_parsed_mount_data *data;
int error = -ENOMEM;
- data = nfs_alloc_parsed_mount_data(0);
+ data = nfs_alloc_parsed_mount_data(4);
if (data == NULL)
goto out_free_data;
@@ -2690,7 +2689,6 @@ static void nfs4_kill_super(struct super_block *sb)
dprintk("--> %s\n", __func__);
nfs_super_return_all_delegations(sb);
kill_anon_super(sb);
- nfs4_renewd_prepare_shutdown(server);
nfs_fscache_release_super_cookie(sb);
nfs_free_server(server);
dprintk("<-- %s\n", __func__);
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/nfs4state.c b/fs/nfsd/nfs4state.c
index 2153f9bdbebd..fcb9817881a1 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 */
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..638573968dcf 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);
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index f38fee0311a7..7b685e10cbad 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -248,11 +248,19 @@ ssize_t part_stat_show(struct device *dev,
part_stat_read(p, merges[WRITE]),
(unsigned long long)part_stat_read(p, sectors[WRITE]),
jiffies_to_msecs(part_stat_read(p, ticks[WRITE])),
- p->in_flight,
+ part_in_flight(p),
jiffies_to_msecs(part_stat_read(p, io_ticks)),
jiffies_to_msecs(part_stat_read(p, time_in_queue)));
}
+ssize_t part_inflight_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct hd_struct *p = dev_to_part(dev);
+
+ return sprintf(buf, "%8u %8u\n", p->in_flight[0], p->in_flight[1]);
+}
+
#ifdef CONFIG_FAIL_MAKE_REQUEST
ssize_t part_fail_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -281,6 +289,7 @@ static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL);
static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL);
static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL);
static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL);
+static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL);
#ifdef CONFIG_FAIL_MAKE_REQUEST
static struct device_attribute dev_attr_fail =
__ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store);
@@ -292,6 +301,7 @@ static struct attribute *part_attrs[] = {
&dev_attr_size.attr,
&dev_attr_alignment_offset.attr,
&dev_attr_stat.attr,
+ &dev_attr_inflight.attr,
#ifdef CONFIG_FAIL_MAKE_REQUEST
&dev_attr_fail.attr,
#endif
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index 56013371f9f3..a44a7897fd4d 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -23,7 +23,6 @@
#include <asm/io.h>
#include <linux/list.h>
#include <linux/ioport.h>
-#include <linux/mm.h>
#include <linux/memory.h>
#include <asm/sections.h>
diff --git a/fs/proc/page.c b/fs/proc/page.c
index 2281c2cbfe2b..5033ce0d254b 100644
--- a/fs/proc/page.c
+++ b/fs/proc/page.c
@@ -94,6 +94,7 @@ static const struct file_operations proc_kpagecount_operations = {
#define KPF_COMPOUND_TAIL 16
#define KPF_HUGE 17
#define KPF_UNEVICTABLE 18
+#define KPF_HWPOISON 19
#define KPF_NOPAGE 20
#define KPF_KSM 21
@@ -180,6 +181,10 @@ static u64 get_uflags(struct page *page)
u |= kpf_copy_bit(k, KPF_UNEVICTABLE, PG_unevictable);
u |= kpf_copy_bit(k, KPF_MLOCKED, PG_mlocked);
+#ifdef CONFIG_MEMORY_FAILURE
+ u |= kpf_copy_bit(k, KPF_HWPOISON, PG_hwpoison);
+#endif
+
#ifdef CONFIG_IA64_UNCACHED_ALLOCATOR
u |= kpf_copy_bit(k, KPF_UNCACHED, PG_uncached);
#endif
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/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/romfs/storage.c b/fs/romfs/storage.c
index b3208adf8e71..71e2b4d50a0a 100644
--- a/fs/romfs/storage.c
+++ b/fs/romfs/storage.c
@@ -253,11 +253,11 @@ ssize_t romfs_dev_strnlen(struct super_block *sb,
#ifdef CONFIG_ROMFS_ON_MTD
if (sb->s_mtd)
- return romfs_mtd_strnlen(sb, pos, limit);
+ return romfs_mtd_strnlen(sb, pos, maxlen);
#endif
#ifdef CONFIG_ROMFS_ON_BLOCK
if (sb->s_bdev)
- return romfs_blk_strnlen(sb, pos, limit);
+ return romfs_blk_strnlen(sb, pos, maxlen);
#endif
return -EIO;
}
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 0050fc40e8c9..5fad489ce5bc 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -894,7 +894,8 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
mutex_lock(&sysfs_rename_mutex);
BUG_ON(!sd->s_parent);
- new_parent_sd = new_parent_kobj->sd ? new_parent_kobj->sd : &sysfs_root;
+ new_parent_sd = (new_parent_kobj && new_parent_kobj->sd) ?
+ new_parent_kobj->sd : &sysfs_root;
error = 0;
if (sd->s_parent == new_parent_sd)
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index 561a9c050cef..f5ea4680f15f 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -268,7 +268,7 @@ static int sysfs_get_open_dirent(struct sysfs_dirent *sd,
struct sysfs_open_dirent *od, *new_od = NULL;
retry:
- spin_lock(&sysfs_open_dirent_lock);
+ spin_lock_irq(&sysfs_open_dirent_lock);
if (!sd->s_attr.open && new_od) {
sd->s_attr.open = new_od;
@@ -281,7 +281,7 @@ static int sysfs_get_open_dirent(struct sysfs_dirent *sd,
list_add_tail(&buffer->list, &od->buffers);
}
- spin_unlock(&sysfs_open_dirent_lock);
+ spin_unlock_irq(&sysfs_open_dirent_lock);
if (od) {
kfree(new_od);
@@ -315,8 +315,9 @@ static void sysfs_put_open_dirent(struct sysfs_dirent *sd,
struct sysfs_buffer *buffer)
{
struct sysfs_open_dirent *od = sd->s_attr.open;
+ unsigned long flags;
- spin_lock(&sysfs_open_dirent_lock);
+ spin_lock_irqsave(&sysfs_open_dirent_lock, flags);
list_del(&buffer->list);
if (atomic_dec_and_test(&od->refcnt))
@@ -324,7 +325,7 @@ static void sysfs_put_open_dirent(struct sysfs_dirent *sd,
else
od = NULL;
- spin_unlock(&sysfs_open_dirent_lock);
+ spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags);
kfree(od);
}
@@ -456,8 +457,9 @@ static unsigned int sysfs_poll(struct file *filp, poll_table *wait)
void sysfs_notify_dirent(struct sysfs_dirent *sd)
{
struct sysfs_open_dirent *od;
+ unsigned long flags;
- spin_lock(&sysfs_open_dirent_lock);
+ spin_lock_irqsave(&sysfs_open_dirent_lock, flags);
od = sd->s_attr.open;
if (od) {
@@ -465,7 +467,7 @@ void sysfs_notify_dirent(struct sysfs_dirent *sd)
wake_up_interruptible(&od->poll);
}
- spin_unlock(&sysfs_open_dirent_lock);
+ spin_unlock_irqrestore(&sysfs_open_dirent_lock, flags);
}
EXPORT_SYMBOL_GPL(sysfs_notify_dirent);
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_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 381854461b28..c2e30eea74dc 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -186,19 +186,37 @@ xfs_destroy_ioend(
}
/*
+ * If the end of the current ioend is beyond the current EOF,
+ * return the new EOF value, otherwise zero.
+ */
+STATIC xfs_fsize_t
+xfs_ioend_new_eof(
+ xfs_ioend_t *ioend)
+{
+ xfs_inode_t *ip = XFS_I(ioend->io_inode);
+ xfs_fsize_t isize;
+ xfs_fsize_t bsize;
+
+ bsize = ioend->io_offset + ioend->io_size;
+ isize = MAX(ip->i_size, ip->i_new_size);
+ isize = MIN(isize, bsize);
+ return isize > ip->i_d.di_size ? isize : 0;
+}
+
+/*
* Update on-disk file size now that data has been written to disk.
* The current in-memory file size is i_size. If a write is beyond
* eof i_new_size will be the intended file size until i_size is
* updated. If this write does not extend all the way to the valid
* file size then restrict this update to the end of the write.
*/
+
STATIC void
xfs_setfilesize(
xfs_ioend_t *ioend)
{
xfs_inode_t *ip = XFS_I(ioend->io_inode);
xfs_fsize_t isize;
- xfs_fsize_t bsize;
ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFREG);
ASSERT(ioend->io_type != IOMAP_READ);
@@ -206,16 +224,10 @@ xfs_setfilesize(
if (unlikely(ioend->io_error))
return;
- bsize = ioend->io_offset + ioend->io_size;
-
xfs_ilock(ip, XFS_ILOCK_EXCL);
-
- isize = MAX(ip->i_size, ip->i_new_size);
- isize = MIN(isize, bsize);
-
- if (ip->i_d.di_size < isize) {
+ isize = xfs_ioend_new_eof(ioend);
+ if (isize) {
ip->i_d.di_size = isize;
- ip->i_update_core = 1;
xfs_mark_inode_dirty_sync(ip);
}
@@ -404,10 +416,16 @@ xfs_submit_ioend_bio(
struct bio *bio)
{
atomic_inc(&ioend->io_remaining);
-
bio->bi_private = ioend;
bio->bi_end_io = xfs_end_bio;
+ /*
+ * If the I/O is beyond EOF we mark the inode dirty immediately
+ * but don't update the inode size until I/O completion.
+ */
+ if (xfs_ioend_new_eof(ioend))
+ xfs_mark_inode_dirty_sync(XFS_I(ioend->io_inode));
+
submit_bio(WRITE, bio);
ASSERT(!bio_flagged(bio, BIO_EOPNOTSUPP));
bio_put(bio);
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 629370974e57..eff61e2732af 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -176,14 +176,7 @@ xfs_file_fsync(
struct dentry *dentry,
int datasync)
{
- struct inode *inode = dentry->d_inode;
- struct xfs_inode *ip = XFS_I(inode);
- int error;
-
- /* capture size updates in I/O completion before writing the inode. */
- error = filemap_fdatawait(inode->i_mapping);
- if (error)
- return error;
+ struct xfs_inode *ip = XFS_I(dentry->d_inode);
xfs_iflags_clear(ip, XFS_ITRUNCATED);
return -xfs_fsync(ip);
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index da0159d99f82..cd42ef78f6b5 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -57,19 +57,22 @@
#include <linux/fiemap.h>
/*
- * Bring the atime in the XFS inode uptodate.
- * Used before logging the inode to disk or when the Linux inode goes away.
+ * Bring the timestamps in the XFS inode uptodate.
+ *
+ * Used before writing the inode to disk.
*/
void
-xfs_synchronize_atime(
+xfs_synchronize_times(
xfs_inode_t *ip)
{
struct inode *inode = VFS_I(ip);
- if (!(inode->i_state & I_CLEAR)) {
- ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec;
- ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec;
- }
+ ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec;
+ ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec;
+ ip->i_d.di_ctime.t_sec = (__int32_t)inode->i_ctime.tv_sec;
+ ip->i_d.di_ctime.t_nsec = (__int32_t)inode->i_ctime.tv_nsec;
+ ip->i_d.di_mtime.t_sec = (__int32_t)inode->i_mtime.tv_sec;
+ ip->i_d.di_mtime.t_nsec = (__int32_t)inode->i_mtime.tv_nsec;
}
/*
@@ -106,32 +109,20 @@ xfs_ichgtime(
if ((flags & XFS_ICHGTIME_MOD) &&
!timespec_equal(&inode->i_mtime, &tv)) {
inode->i_mtime = tv;
- ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec;
- ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec;
sync_it = 1;
}
if ((flags & XFS_ICHGTIME_CHG) &&
!timespec_equal(&inode->i_ctime, &tv)) {
inode->i_ctime = tv;
- ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec;
- ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec;
sync_it = 1;
}
/*
- * We update the i_update_core field _after_ changing
- * the timestamps in order to coordinate properly with
- * xfs_iflush() so that we don't lose timestamp updates.
- * This keeps us from having to hold the inode lock
- * while doing this. We use the SYNCHRONIZE macro to
- * ensure that the compiler does not reorder the update
- * of i_update_core above the timestamp updates above.
+ * Update complete - now make sure everyone knows that the inode
+ * is dirty.
*/
- if (sync_it) {
- SYNCHRONIZE();
- ip->i_update_core = 1;
+ if (sync_it)
xfs_mark_inode_dirty_sync(ip);
- }
}
/*
@@ -506,10 +497,8 @@ xfs_vn_getattr(
stat->gid = ip->i_d.di_gid;
stat->ino = ip->i_ino;
stat->atime = inode->i_atime;
- stat->mtime.tv_sec = ip->i_d.di_mtime.t_sec;
- stat->mtime.tv_nsec = ip->i_d.di_mtime.t_nsec;
- stat->ctime.tv_sec = ip->i_d.di_ctime.t_sec;
- stat->ctime.tv_nsec = ip->i_d.di_ctime.t_nsec;
+ stat->mtime = inode->i_mtime;
+ stat->ctime = inode->i_ctime;
stat->blocks =
XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks);
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index 49e4a6aea73c..072050f8d346 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -667,7 +667,7 @@ start:
xip->i_new_size = new_size;
if (likely(!(ioflags & IO_INVIS)))
- xfs_ichgtime(xip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
+ file_update_time(file);
/*
* If the offset is beyond the size of the file, we have a couple
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index bdd41c8c342f..18a4b8e11df2 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -977,6 +977,28 @@ xfs_fs_inode_init_once(
}
/*
+ * Dirty the XFS inode when mark_inode_dirty_sync() is called so that
+ * we catch unlogged VFS level updates to the inode. Care must be taken
+ * here - the transaction code calls mark_inode_dirty_sync() to mark the
+ * VFS inode dirty in a transaction and clears the i_update_core field;
+ * it must clear the field after calling mark_inode_dirty_sync() to
+ * correctly indicate that the dirty state has been propagated into the
+ * inode log item.
+ *
+ * We need the barrier() to maintain correct ordering between unlogged
+ * updates and the transaction commit code that clears the i_update_core
+ * field. This requires all updates to be completed before marking the
+ * inode dirty.
+ */
+STATIC void
+xfs_fs_dirty_inode(
+ struct inode *inode)
+{
+ barrier();
+ XFS_I(inode)->i_update_core = 1;
+}
+
+/*
* Attempt to flush the inode, this will actually fail
* if the inode is pinned, but we dirty the inode again
* at the point when it is unpinned after a log write,
@@ -1126,7 +1148,7 @@ xfs_fs_put_super(
}
STATIC int
-xfs_fs_sync_super(
+xfs_fs_sync_fs(
struct super_block *sb,
int wait)
{
@@ -1134,23 +1156,23 @@ xfs_fs_sync_super(
int error;
/*
- * Treat a sync operation like a freeze. This is to work
- * around a race in sync_inodes() which works in two phases
- * - an asynchronous flush, which can write out an inode
- * without waiting for file size updates to complete, and a
- * synchronous flush, which wont do anything because the
- * async flush removed the inode's dirty flag. Also
- * sync_inodes() will not see any files that just have
- * outstanding transactions to be flushed because we don't
- * dirty the Linux inode until after the transaction I/O
- * completes.
+ * Not much we can do for the first async pass. Writing out the
+ * superblock would be counter-productive as we are going to redirty
+ * when writing out other data and metadata (and writing out a single
+ * block is quite fast anyway).
+ *
+ * Try to asynchronously kick off quota syncing at least.
*/
- if (wait || unlikely(sb->s_frozen == SB_FREEZE_WRITE))
- error = xfs_quiesce_data(mp);
- else
- error = xfs_sync_fsdata(mp, 0);
+ if (!wait) {
+ xfs_qm_sync(mp, SYNC_TRYLOCK);
+ return 0;
+ }
+
+ error = xfs_quiesce_data(mp);
+ if (error)
+ return -error;
- if (unlikely(laptop_mode)) {
+ if (laptop_mode) {
int prev_sync_seq = mp->m_sync_seq;
/*
@@ -1169,7 +1191,7 @@ xfs_fs_sync_super(
mp->m_sync_seq != prev_sync_seq);
}
- return -error;
+ return 0;
}
STATIC int
@@ -1539,10 +1561,11 @@ xfs_fs_get_sb(
static const struct super_operations xfs_super_operations = {
.alloc_inode = xfs_fs_alloc_inode,
.destroy_inode = xfs_fs_destroy_inode,
+ .dirty_inode = xfs_fs_dirty_inode,
.write_inode = xfs_fs_write_inode,
.clear_inode = xfs_fs_clear_inode,
.put_super = xfs_fs_put_super,
- .sync_fs = xfs_fs_sync_super,
+ .sync_fs = xfs_fs_sync_fs,
.freeze_fs = xfs_fs_freeze,
.statfs = xfs_fs_statfs,
.remount_fs = xfs_fs_remount,
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index 320be6aea492..961df0a22c78 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -309,11 +309,15 @@ xfs_sync_attr(
STATIC int
xfs_commit_dummy_trans(
struct xfs_mount *mp,
- uint log_flags)
+ uint flags)
{
struct xfs_inode *ip = mp->m_rootip;
struct xfs_trans *tp;
int error;
+ int log_flags = XFS_LOG_FORCE;
+
+ if (flags & SYNC_WAIT)
+ log_flags |= XFS_LOG_SYNC;
/*
* Put a dummy transaction in the log to tell recovery
@@ -331,13 +335,12 @@ xfs_commit_dummy_trans(
xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
xfs_trans_ihold(tp, ip);
xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
- /* XXX(hch): ignoring the error here.. */
error = xfs_trans_commit(tp, 0);
-
xfs_iunlock(ip, XFS_ILOCK_EXCL);
+ /* the log force ensures this transaction is pushed to disk */
xfs_log_force(mp, 0, log_flags);
- return 0;
+ return error;
}
int
@@ -385,7 +388,20 @@ xfs_sync_fsdata(
else
XFS_BUF_ASYNC(bp);
- return xfs_bwrite(mp, bp);
+ error = xfs_bwrite(mp, bp);
+ if (error)
+ return error;
+
+ /*
+ * If this is a data integrity sync make sure all pending buffers
+ * are flushed out for the log coverage check below.
+ */
+ if (flags & SYNC_WAIT)
+ xfs_flush_buftarg(mp->m_ddev_targp, 1);
+
+ if (xfs_log_need_covered(mp))
+ error = xfs_commit_dummy_trans(mp, flags);
+ return error;
out_brelse:
xfs_buf_relse(bp);
@@ -419,14 +435,16 @@ xfs_quiesce_data(
/* push non-blocking */
xfs_sync_data(mp, 0);
xfs_qm_sync(mp, SYNC_TRYLOCK);
- xfs_filestream_flush(mp);
- /* push and block */
+ /* push and block till complete */
xfs_sync_data(mp, SYNC_WAIT);
xfs_qm_sync(mp, SYNC_WAIT);
+ /* drop inode references pinned by filestreams */
+ xfs_filestream_flush(mp);
+
/* write superblock and hoover up shutdown errors */
- error = xfs_sync_fsdata(mp, 0);
+ error = xfs_sync_fsdata(mp, SYNC_WAIT);
/* flush data-only devices */
if (mp->m_rtdev_targp)
@@ -570,8 +588,6 @@ xfs_sync_worker(
/* dgc: errors ignored here */
error = xfs_qm_sync(mp, SYNC_TRYLOCK);
error = xfs_sync_fsdata(mp, SYNC_TRYLOCK);
- if (xfs_log_need_covered(mp))
- error = xfs_commit_dummy_trans(mp, XFS_LOG_FORCE);
}
mp->m_sync_seq++;
wake_up(&mp->m_wait_single_sync_task);
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_dfrag.c b/fs/xfs/xfs_dfrag.c
index 7465f9ee125f..ab89a7e94a0f 100644
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -206,10 +206,10 @@ xfs_swap_extents(
* process that the file was not changed out from
* under it.
*/
- if ((sbp->bs_ctime.tv_sec != ip->i_d.di_ctime.t_sec) ||
- (sbp->bs_ctime.tv_nsec != ip->i_d.di_ctime.t_nsec) ||
- (sbp->bs_mtime.tv_sec != ip->i_d.di_mtime.t_sec) ||
- (sbp->bs_mtime.tv_nsec != ip->i_d.di_mtime.t_nsec)) {
+ if ((sbp->bs_ctime.tv_sec != VFS_I(ip)->i_ctime.tv_sec) ||
+ (sbp->bs_ctime.tv_nsec != VFS_I(ip)->i_ctime.tv_nsec) ||
+ (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) ||
+ (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) {
error = XFS_ERROR(EBUSY);
goto out_unlock;
}
diff --git a/fs/xfs/xfs_dir2_leaf.c b/fs/xfs/xfs_dir2_leaf.c
index fa913e459442..41ad537c49e9 100644
--- a/fs/xfs/xfs_dir2_leaf.c
+++ b/fs/xfs/xfs_dir2_leaf.c
@@ -854,6 +854,7 @@ xfs_dir2_leaf_getdents(
*/
ra_want = howmany(bufsize + mp->m_dirblksize,
mp->m_sb.sb_blocksize) - 1;
+ ASSERT(ra_want >= 0);
/*
* If we don't have as many as we want, and we haven't
@@ -1088,7 +1089,8 @@ xfs_dir2_leaf_getdents(
*/
ptr += length;
curoff += length;
- bufsize -= length;
+ /* bufsize may have just been a guess; don't go negative */
+ bufsize = bufsize > length ? bufsize - length : 0;
}
/*
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index c1dc7ef5a1d8..b92a4fa2a0a1 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -3068,9 +3068,9 @@ xfs_iflush_int(
SYNCHRONIZE();
/*
- * Make sure to get the latest atime from the Linux inode.
+ * Make sure to get the latest timestamps from the Linux inode.
*/
- xfs_synchronize_atime(ip);
+ xfs_synchronize_times(ip);
if (XFS_TEST_ERROR(be16_to_cpu(dip->di_magic) != XFS_DINODE_MAGIC,
mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) {
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 0b38b9a869ec..41555de1d1db 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -504,7 +504,7 @@ void xfs_ichgtime(xfs_inode_t *, int);
void xfs_lock_inodes(xfs_inode_t **, int, uint);
void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
-void xfs_synchronize_atime(xfs_inode_t *);
+void xfs_synchronize_times(xfs_inode_t *);
void xfs_mark_inode_dirty_sync(xfs_inode_t *);
#if defined(XFS_INODE_TRACE)
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 47d5b663c37e..9794b876d6ff 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -232,6 +232,15 @@ xfs_inode_item_format(
nvecs = 1;
/*
+ * Make sure the linux inode is dirty. We do this before
+ * clearing i_update_core as the VFS will call back into
+ * XFS here and set i_update_core, so we need to dirty the
+ * inode first so that the ordering of i_update_core and
+ * unlogged modifications still works as described below.
+ */
+ xfs_mark_inode_dirty_sync(ip);
+
+ /*
* Clear i_update_core if the timestamps (or any other
* non-transactional modification) need flushing/logging
* and we're about to log them with the rest of the core.
@@ -263,14 +272,9 @@ xfs_inode_item_format(
}
/*
- * Make sure to get the latest atime from the Linux inode.
+ * Make sure to get the latest timestamps from the Linux inode.
*/
- xfs_synchronize_atime(ip);
-
- /*
- * make sure the linux inode is dirty
- */
- xfs_mark_inode_dirty_sync(ip);
+ xfs_synchronize_times(ip);
vecp->i_addr = (xfs_caddr_t)&ip->i_d;
vecp->i_len = sizeof(struct xfs_icdinode);
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index b68f9107e26c..62efab2f3839 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -59,6 +59,7 @@ xfs_bulkstat_one_iget(
{
xfs_icdinode_t *dic; /* dinode core info pointer */
xfs_inode_t *ip; /* incore inode pointer */
+ struct inode *inode;
int error;
error = xfs_iget(mp, NULL, ino,
@@ -72,6 +73,7 @@ xfs_bulkstat_one_iget(
ASSERT(ip->i_imap.im_blkno != 0);
dic = &ip->i_d;
+ inode = VFS_I(ip);
/* xfs_iget returns the following without needing
* further change.
@@ -83,16 +85,19 @@ xfs_bulkstat_one_iget(
buf->bs_uid = dic->di_uid;
buf->bs_gid = dic->di_gid;
buf->bs_size = dic->di_size;
+
/*
- * We are reading the atime from the Linux inode because the
- * dinode might not be uptodate.
+ * We need to read the timestamps from the Linux inode because
+ * the VFS keeps writing directly into the inode structure instead
+ * of telling us about the updates.
*/
- buf->bs_atime.tv_sec = VFS_I(ip)->i_atime.tv_sec;
- buf->bs_atime.tv_nsec = VFS_I(ip)->i_atime.tv_nsec;
- buf->bs_mtime.tv_sec = dic->di_mtime.t_sec;
- buf->bs_mtime.tv_nsec = dic->di_mtime.t_nsec;
- buf->bs_ctime.tv_sec = dic->di_ctime.t_sec;
- buf->bs_ctime.tv_nsec = dic->di_ctime.t_nsec;
+ buf->bs_atime.tv_sec = inode->i_atime.tv_sec;
+ buf->bs_atime.tv_nsec = inode->i_atime.tv_nsec;
+ buf->bs_mtime.tv_sec = inode->i_mtime.tv_sec;
+ buf->bs_mtime.tv_nsec = inode->i_mtime.tv_nsec;
+ buf->bs_ctime.tv_sec = inode->i_ctime.tv_sec;
+ buf->bs_ctime.tv_nsec = inode->i_ctime.tv_nsec;
+
buf->bs_xflags = xfs_ip2xflags(ip);
buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog;
buf->bs_extents = dic->di_nextents;
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index a434f287962d..b572f7e840e0 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -2476,12 +2476,6 @@ xfs_reclaim(
ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0);
/*
- * Make sure the atime in the XFS inode is correct before freeing the
- * Linux inode.
- */
- xfs_synchronize_atime(ip);
-
- /*
* If we have nothing to flush with this inode then complete the
* teardown now, otherwise break the link between the xfs inode and the
* linux inode and clean up the xfs inode later. This avoids flushing
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/hardirq.h b/include/asm-generic/hardirq.h
index 23bb4dad4962..62f59080e5cc 100644
--- a/include/asm-generic/hardirq.h
+++ b/include/asm-generic/hardirq.h
@@ -6,7 +6,7 @@
#include <linux/irq.h>
typedef struct {
- unsigned long __softirq_pending;
+ unsigned int __softirq_pending;
} ____cacheline_aligned irq_cpustat_t;
#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
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/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h
index ef47dfd8e5e9..b29e20168b5f 100644
--- a/include/drm/drm_crtc_helper.h
+++ b/include/drm/drm_crtc_helper.h
@@ -61,6 +61,9 @@ struct drm_crtc_helper_funcs {
/* Move the crtc on the current fb to the given position *optional* */
int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb);
+
+ /* reload the current crtc LUT */
+ void (*load_lut)(struct drm_crtc *crtc);
};
struct drm_encoder_helper_funcs {
diff --git a/include/drm/drm_fb_helper.h b/include/drm/drm_fb_helper.h
index 4aa5740ce59f..58c892a2cbfa 100644
--- a/include/drm/drm_fb_helper.h
+++ b/include/drm/drm_fb_helper.h
@@ -39,6 +39,8 @@ struct drm_fb_helper_crtc {
struct drm_fb_helper_funcs {
void (*gamma_set)(struct drm_crtc *crtc, u16 red, u16 green,
u16 blue, int regno);
+ void (*gamma_get)(struct drm_crtc *crtc, u16 *red, u16 *green,
+ u16 *blue, int regno);
};
/* mode specified on the command line */
@@ -71,6 +73,7 @@ struct drm_fb_helper {
};
int drm_fb_helper_single_fb_probe(struct drm_device *dev,
+ int preferred_bpp,
int (*fb_create)(struct drm_device *dev,
uint32_t fb_width,
uint32_t fb_height,
@@ -98,9 +101,11 @@ int drm_fb_helper_setcolreg(unsigned regno,
void drm_fb_helper_restore(void);
void drm_fb_helper_fill_var(struct fb_info *info, struct drm_framebuffer *fb,
uint32_t fb_width, uint32_t fb_height);
-void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch);
+void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
+ uint32_t depth);
int drm_fb_helper_add_connector(struct drm_connector *connector);
int drm_fb_helper_parse_command_line(struct drm_device *dev);
+int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
#endif
diff --git a/include/drm/drm_pciids.h b/include/drm/drm_pciids.h
index 3f6e545609be..e6f3b120f51a 100644
--- a/include/drm/drm_pciids.h
+++ b/include/drm/drm_pciids.h
@@ -80,7 +80,7 @@
{0x1002, 0x5158, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200}, \
{0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
{0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
- {0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
+ {0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_SINGLE_CRTC}, \
{0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
{0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
{0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
@@ -113,7 +113,7 @@
{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
- {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
+ {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_SINGLE_CRTC}, \
{0x1002, 0x5a41, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART}, \
{0x1002, 0x5a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \
{0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_IGPGART}, \
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index cff4a101f266..1feed71551c9 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -126,6 +126,7 @@ header-y += nfs_mount.h
header-y += nl80211.h
header-y += param.h
header-y += pci_regs.h
+header-y += perf_event.h
header-y += pfkeyv2.h
header-y += pg.h
header-y += phantom.h
@@ -363,6 +364,7 @@ unifdef-y += utsname.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/ata.h b/include/linux/ata.h
index 6299a259ed19..4fb357312b3b 100644
--- a/include/linux/ata.h
+++ b/include/linux/ata.h
@@ -334,9 +334,12 @@ enum {
SETFEATURES_SATA_DISABLE = 0x90, /* Disable use of SATA feature */
/* SETFEATURE Sector counts for SATA features */
- SATA_AN = 0x05, /* Asynchronous Notification */
- SATA_DIPM = 0x03, /* Device Initiated Power Management */
- SATA_FPDMA_AA = 0x02, /* DMA Setup FIS Auto-Activate */
+ SATA_FPDMA_OFFSET = 0x01, /* FPDMA non-zero buffer offsets */
+ SATA_FPDMA_AA = 0x02, /* FPDMA Setup FIS Auto-Activate */
+ SATA_DIPM = 0x03, /* Device Initiated Power Management */
+ SATA_FPDMA_IN_ORDER = 0x04, /* FPDMA in-order data delivery */
+ SATA_AN = 0x05, /* Asynchronous Notification */
+ SATA_SSP = 0x06, /* Software Settings Preservation */
/* feature values for SET_MAX */
ATA_SET_MAX_ADDR = 0x00,
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 25119041e034..221cecd86bd3 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1172,11 +1172,7 @@ static inline void put_dev_sector(Sector p)
}
struct work_struct;
-struct delayed_work;
int kblockd_schedule_work(struct request_queue *q, struct work_struct *work);
-int kblockd_schedule_delayed_work(struct request_queue *q,
- struct delayed_work *work,
- unsigned long delay);
#define MODULE_ALIAS_BLOCKDEV(major,minor) \
MODULE_ALIAS("block-major-" __stringify(major) "-" __stringify(minor))
diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h
index 5824b20b5fcb..1d3f7f00e3af 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,9 @@ 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);
#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/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/elf.h b/include/linux/elf.h
index 45a937be6d38..90a4ed0ea0e5 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -361,6 +361,7 @@ typedef struct elf64_shdr {
#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
+#define NT_PRXSTATUS 0x300 /* s390 upper register halves */
/* Note header in a PT_NOTE section */
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/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/ftrace.h b/include/linux/ftrace.h
index cd3d2abaf30a..0b4f97d24d7f 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -241,7 +241,7 @@ extern void ftrace_enable_daemon(void);
# define ftrace_set_filter(buf, len, reset) do { } while (0)
# define ftrace_disable_daemon() do { } while (0)
# define ftrace_enable_daemon() do { } while (0)
-static inline void ftrace_release(void *start, unsigned long size) { }
+static inline void ftrace_release_mod(struct module *mod) {}
static inline int register_ftrace_command(struct ftrace_func_command *cmd)
{
return -EINVAL;
diff --git a/include/linux/futex.h b/include/linux/futex.h
index 8ec17997d94f..1e5a26d79232 100644
--- a/include/linux/futex.h
+++ b/include/linux/futex.h
@@ -33,8 +33,8 @@
#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG)
#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG)
#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG)
-#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITS | FUTEX_PRIVATE_FLAG)
-#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITS | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG)
+#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG)
#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \
FUTEX_PRIVATE_FLAG)
#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index 7beaa21b3880..297df45ffd0a 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -98,7 +98,7 @@ struct hd_struct {
int make_it_fail;
#endif
unsigned long stamp;
- int in_flight;
+ int in_flight[2];
#ifdef CONFIG_SMP
struct disk_stats *dkstats;
#else
@@ -322,18 +322,23 @@ static inline void free_part_stats(struct hd_struct *part)
#define part_stat_sub(cpu, gendiskp, field, subnd) \
part_stat_add(cpu, gendiskp, field, -subnd)
-static inline void part_inc_in_flight(struct hd_struct *part)
+static inline void part_inc_in_flight(struct hd_struct *part, int rw)
{
- part->in_flight++;
+ part->in_flight[rw]++;
if (part->partno)
- part_to_disk(part)->part0.in_flight++;
+ part_to_disk(part)->part0.in_flight[rw]++;
}
-static inline void part_dec_in_flight(struct hd_struct *part)
+static inline void part_dec_in_flight(struct hd_struct *part, int rw)
{
- part->in_flight--;
+ part->in_flight[rw]--;
if (part->partno)
- part_to_disk(part)->part0.in_flight--;
+ part_to_disk(part)->part0.in_flight[rw]--;
+}
+
+static inline int part_in_flight(struct hd_struct *part)
+{
+ return part->in_flight[0] + part->in_flight[1];
}
/* block/blk-core.c */
@@ -546,6 +551,8 @@ extern ssize_t part_size_show(struct device *dev,
struct device_attribute *attr, char *buf);
extern ssize_t part_stat_show(struct device *dev,
struct device_attribute *attr, char *buf);
+extern ssize_t part_inflight_show(struct device *dev,
+ struct device_attribute *attr, char *buf);
#ifdef CONFIG_FAIL_MAKE_REQUEST
extern ssize_t part_fail_show(struct device *dev,
struct device_attribute *attr, char *buf);
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 2d02dfd7076c..508824ee35e6 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -349,11 +349,11 @@ struct twl4030_madc_platform_data {
int irq_line;
};
-/* Boards have uniqe mappings of {col, row} --> keycode.
- * Column and row are 4 bits, but range only from 0..7.
+/* Boards have uniqe mappings of {row, col} --> keycode.
+ * Column and row are 8 bits each, but range only from 0..7.
* a PERSISTENT_KEY is "always on" and never reported.
*/
-#define PERSISTENT_KEY(c, r) KEY((c), (r), KEY_RESERVED)
+#define PERSISTENT_KEY(r, c) KEY((r), (c), KEY_RESERVED)
struct twl4030_keypad_data {
const struct matrix_keymap_data *keymap_data;
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/init.h b/include/linux/init.h
index 400adbb45414..ff8bde520d03 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -271,6 +271,7 @@ void __init parse_early_options(char *cmdline);
#else /* MODULE */
/* Don't use these in modules, but some people do... */
+#define early_initcall(fn) module_init(fn)
#define core_initcall(fn) module_init(fn)
#define postcore_initcall(fn) module_init(fn)
#define arch_initcall(fn) module_init(fn)
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index b78cf8194957..7ca72b74eec7 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -10,7 +10,6 @@
#include <linux/irqreturn.h>
#include <linux/irqnr.h>
#include <linux/hardirq.h>
-#include <linux/sched.h>
#include <linux/irqflags.h>
#include <linux/smp.h>
#include <linux/percpu.h>
@@ -610,6 +609,7 @@ extern void debug_poll_all_shared_irqs(void);
static inline void debug_poll_all_shared_irqs(void) { }
#endif
+struct seq_file;
int show_interrupts(struct seq_file *p, void *v);
struct irq_desc;
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index c662efa68289..56404251248c 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
};
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index d3cd23f30039..f4e3184fa054 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -659,6 +659,12 @@ extern int do_sysinfo(struct sysinfo *info);
#endif /* __KERNEL__ */
+#ifndef __EXPORTED_HEADERS__
+#ifndef __KERNEL__
+#warning Attempt to use kernel headers from user space, see http://kernelnewbies.org/KernelHeaders
+#endif /* __KERNEL__ */
+#endif /* __EXPORTED_HEADERS__ */
+
#define SI_LOAD_SHIFT 16
struct sysinfo {
long uptime; /* Seconds since boot */
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/libata.h b/include/linux/libata.h
index 76319bf03e37..87698640c091 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -418,6 +418,17 @@ enum {
ATA_TIMING_ACTIVE | ATA_TIMING_RECOVER |
ATA_TIMING_DMACK_HOLD | ATA_TIMING_CYCLE |
ATA_TIMING_UDMA,
+
+ /* ACPI constants */
+ ATA_ACPI_FILTER_SETXFER = 1 << 0,
+ ATA_ACPI_FILTER_LOCK = 1 << 1,
+ ATA_ACPI_FILTER_DIPM = 1 << 2,
+ ATA_ACPI_FILTER_FPDMA_OFFSET = 1 << 3, /* FPDMA non-zero offset */
+ ATA_ACPI_FILTER_FPDMA_AA = 1 << 4, /* FPDMA auto activate */
+
+ ATA_ACPI_FILTER_DEFAULT = ATA_ACPI_FILTER_SETXFER |
+ ATA_ACPI_FILTER_LOCK |
+ ATA_ACPI_FILTER_DIPM,
};
enum ata_xfer_mask {
@@ -587,6 +598,7 @@ struct ata_device {
#ifdef CONFIG_ATA_ACPI
acpi_handle acpi_handle;
union acpi_object *gtf_cache;
+ unsigned int gtf_filter;
#endif
/* n_sector is CLEAR_BEGIN, read comment above CLEAR_BEGIN */
u64 n_sectors; /* size of device, if ATA */
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/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/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/wm8350/core.h b/include/linux/mfd/wm8350/core.h
index 1d595de6a055..32197fde904d 100644
--- a/include/linux/mfd/wm8350/core.h
+++ b/include/linux/mfd/wm8350/core.h
@@ -681,6 +681,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/mmc/host.h b/include/linux/mmc/host.h
index 81bb42358595..eaf36364b7d4 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -11,6 +11,7 @@
#define LINUX_MMC_HOST_H
#include <linux/leds.h>
+#include <linux/sched.h>
#include <linux/mmc/core.h>
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/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/net.h b/include/linux/net.h
index 529a0931711d..b42bb60fe92f 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 */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 94958c109761..83800091a31a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -557,7 +557,7 @@ struct netdev_queue {
* Callback uses when the transmitter has not made any progress
* for dev->watchdog ticks.
*
- * struct net_device_stats* (*get_stats)(struct net_device *dev);
+ * struct net_device_stats* (*ndo_get_stats)(struct net_device *dev);
* Called when a user wants to get the network device usage
* statistics. If not defined, the counters in dev->stats will
* be used.
@@ -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/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..da4128f6e916 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -701,6 +701,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 +1247,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 da1fda8623e0..eeb3043c3e4d 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -543,7 +543,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
@@ -776,6 +776,7 @@
#define PCI_DEVICE_ID_TI_X515 0x8036
#define PCI_DEVICE_ID_TI_XX12 0x8039
#define PCI_DEVICE_ID_TI_XX12_FM 0x803b
+#define PCI_DEVICE_ID_TI_XIO2000A 0x8231
#define PCI_DEVICE_ID_TI_1130 0xac12
#define PCI_DEVICE_ID_TI_1031 0xac13
#define PCI_DEVICE_ID_TI_1131 0xac15
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 3a9d36d1e92a..2e6d95f97419 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -442,6 +442,7 @@ enum perf_callchain_context {
#include <linux/hrtimer.h>
#include <linux/fs.h>
#include <linux/pid_namespace.h>
+#include <linux/workqueue.h>
#include <asm/atomic.h>
#define PERF_MAX_STACK_DEPTH 255
@@ -513,6 +514,10 @@ struct file;
struct perf_mmap_data {
struct rcu_head rcu_head;
+#ifdef CONFIG_PERF_USE_VMALLOC
+ struct work_struct work;
+#endif
+ int data_order;
int nr_pages; /* nr of data pages */
int writable; /* are we writable */
int nr_locked; /* nr pages mlocked */
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/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 6fe0363724e9..af5b8af505bf 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);
@@ -77,7 +68,7 @@ extern int rcu_scheduler_active;
#error "Unknown RCU implementation specified to kernel configuration"
#endif
-#define RCU_HEAD_INIT { .next = NULL, .func = NULL }
+#define RCU_HEAD_INIT { .next = NULL, .func = NULL }
#define RCU_HEAD(head) struct rcu_head head = RCU_HEAD_INIT
#define INIT_RCU_HEAD(ptr) do { \
(ptr)->next = NULL; (ptr)->func = NULL; \
@@ -129,12 +120,6 @@ static inline void rcu_read_lock(void)
rcu_read_acquire();
}
-/**
- * rcu_read_unlock - marks the end of an RCU read-side critical section.
- *
- * See rcu_read_lock() for more information.
- */
-
/*
* So where is rcu_write_lock()? It does not exist, as there is no
* way for writers to lock out RCU readers. This is a feature, not
@@ -144,6 +129,12 @@ static inline void rcu_read_lock(void)
* used as well. RCU does not care how the writers keep out of each
* others' way, as long as they do so.
*/
+
+/**
+ * rcu_read_unlock - marks the end of an RCU read-side critical section.
+ *
+ * See rcu_read_lock() for more information.
+ */
static inline void rcu_read_unlock(void)
{
rcu_read_release();
@@ -196,6 +187,8 @@ static inline void rcu_read_lock_sched(void)
__acquire(RCU_SCHED);
rcu_read_acquire();
}
+
+/* Used by lockdep and tracing: cannot be traced, cannot call lockdep. */
static inline notrace void rcu_read_lock_sched_notrace(void)
{
preempt_disable_notrace();
@@ -213,6 +206,8 @@ static inline void rcu_read_unlock_sched(void)
__release(RCU_SCHED);
preempt_enable();
}
+
+/* Used by lockdep and tracing: cannot be traced, cannot call lockdep. */
static inline notrace void rcu_read_unlock_sched_notrace(void)
{
__release(RCU_SCHED);
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 37682770e9d2..46e9ab3ee6e1 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -30,10 +30,14 @@
#ifndef __LINUX_RCUTREE_H
#define __LINUX_RCUTREE_H
+struct notifier_block;
+
extern void rcu_sched_qs(int cpu);
extern void rcu_bh_qs(int cpu);
-
+extern int rcu_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu);
extern int rcu_needs_cpu(int cpu);
+extern int rcu_expedited_torture_stats(char *page);
#ifdef CONFIG_TREE_PREEMPT_RCU
@@ -85,16 +89,11 @@ static inline void synchronize_rcu_bh_expedited(void)
extern void __rcu_init(void);
extern void rcu_check_callbacks(int cpu, int user);
-extern void rcu_restart_cpu(int cpu);
extern long rcu_batches_completed(void);
extern long rcu_batches_completed_bh(void);
extern long rcu_batches_completed_sched(void);
-static inline void rcu_init_sched(void)
-{
-}
-
#ifdef CONFIG_NO_HZ
void rcu_enter_nohz(void);
void rcu_exit_nohz(void);
@@ -107,7 +106,7 @@ static inline void rcu_exit_nohz(void)
}
#endif /* CONFIG_NO_HZ */
-/* A context switch is a grace period for rcutree. */
+/* A context switch is a grace period for RCU-sched and RCU-bh. */
static inline int rcu_blocking_is_gp(void)
{
return num_online_cpus() == 1;
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/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/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/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 3b461dffe244..59966f12990c 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -16,7 +16,7 @@ struct __kernel_sockaddr_storage {
/* _SS_MAXSIZE value minus size of ss_family */
} __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */
-#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2)
+#ifdef __KERNEL__
#include <asm/socket.h> /* arch-dependent defines */
#include <linux/sockios.h> /* the SIOCxxx I/O controls */
@@ -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
@@ -101,21 +107,6 @@ struct cmsghdr {
((char *)(cmsg) - (char *)(mhdr)->msg_control)))
/*
- * This mess will go away with glibc
- */
-
-#ifdef __KERNEL__
-#define __KINLINE static inline
-#elif defined(__GNUC__)
-#define __KINLINE static __inline__
-#elif defined(__cplusplus)
-#define __KINLINE static inline
-#else
-#define __KINLINE static
-#endif
-
-
-/*
* Get the next cmsg header
*
* PLEASE, do not touch this function. If you think, that it is
@@ -128,7 +119,7 @@ struct cmsghdr {
* ancillary object DATA. --ANK (980731)
*/
-__KINLINE struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size,
+static inline struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size,
struct cmsghdr *__cmsg)
{
struct cmsghdr * __ptr;
@@ -140,7 +131,7 @@ __KINLINE struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size,
return __ptr;
}
-__KINLINE struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg)
+static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg)
{
return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg);
}
@@ -327,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/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..714f063a3e6d 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;
@@ -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/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/serial.h b/include/linux/usb/serial.h
index c17eb64d7213..ce911ebf91e8 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -150,6 +150,7 @@ struct usb_serial {
struct usb_interface *interface;
unsigned char disconnected:1;
unsigned char suspending:1;
+ unsigned char attached:1;
unsigned char minor;
unsigned char num_ports;
unsigned char num_port_pointers;
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/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/workqueue.h b/include/linux/workqueue.h
index 7ef0c7b94f31..cf24c20de9e4 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -207,6 +207,7 @@ extern int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
extern void flush_workqueue(struct workqueue_struct *wq);
extern void flush_scheduled_work(void);
+extern void flush_delayed_work(struct delayed_work *work);
extern int schedule_work(struct work_struct *work);
extern int schedule_work_on(int cpu, struct work_struct *work);
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..9679f05e9896 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;
@@ -35,6 +40,9 @@ 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/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/inet_hashtables.h b/include/net/inet_hashtables.h
index d522dcf3031a..5f11c4a0daca 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(
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..86f1c8bd040c 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 */
};
@@ -42,9 +55,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 466859b285e1..c75b960c8ac8 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1669,6 +1669,8 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw);
* to this function and ieee80211_rx_irqsafe() may not be mixed for a
* single hardware.
*
+ * Note that right now, this function must be called with softirqs disabled.
+ *
* @hw: the hardware this frame came in on
* @skb: the buffer to receive, owned by mac80211 after this call
*/
diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h
index a1202841aadd..699410142bfa 100644
--- a/include/net/net_namespace.h
+++ b/include/net/net_namespace.h
@@ -80,7 +80,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/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/sock.h b/include/net/sock.h
index 1621935aad5b..1364428f53f2 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -226,12 +226,12 @@ struct sock {
#define sk_prot __sk_common.skc_prot
#define sk_net __sk_common.skc_net
kmemcheck_bitfield_begin(flags);
- unsigned char sk_shutdown : 2,
- sk_no_check : 2,
- sk_userlocks : 4;
+ unsigned int sk_shutdown : 2,
+ sk_no_check : 2,
+ sk_userlocks : 4,
+ sk_protocol : 8,
+ sk_type : 16;
kmemcheck_bitfield_end(flags);
- unsigned char sk_protocol;
- unsigned short sk_type;
int sk_rcvbuf;
socket_lock_t sk_lock;
/*
@@ -504,6 +504,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)
@@ -1396,7 +1398,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 +1494,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/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/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 887e57e3e223..a72edd4eceec 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -303,6 +303,7 @@ struct iscsi_session {
int cmds_max; /* size of cmds array */
struct iscsi_task **cmds; /* Original Cmds arr */
struct iscsi_pool cmdpool; /* PDU's pool */
+ void *dd_data; /* LLD private data */
};
enum {
@@ -363,7 +364,7 @@ extern int iscsi_target_alloc(struct scsi_target *starget);
*/
extern struct iscsi_cls_session *
iscsi_session_setup(struct iscsi_transport *, struct Scsi_Host *shost,
- uint16_t, int, uint32_t, unsigned int);
+ uint16_t, int, int, uint32_t, unsigned int);
extern void iscsi_session_teardown(struct iscsi_cls_session *);
extern void iscsi_session_recovery_timedout(struct iscsi_cls_session *);
extern int iscsi_set_param(struct iscsi_cls_conn *cls_conn,
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 084478e14d24..34c46ab5c31b 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -129,6 +129,9 @@ struct scsi_cmnd;
#define MI_REPORT_TARGET_PGS 0x0a
/* values for maintenance out */
#define MO_SET_TARGET_PGS 0x0a
+/* values for variable length command */
+#define READ_32 0x09
+#define WRITE_32 0x0b
/* Values for T10/04-262r7 */
#define ATA_16 0x85 /* 16-byte pass-thru */
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 3878d1dc7f59..a5e885a111df 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -229,10 +229,6 @@ enum scsi_prot_operations {
/* OS-HBA: Protected, HBA-Target: Protected */
SCSI_PROT_READ_PASS,
SCSI_PROT_WRITE_PASS,
-
- /* OS-HBA: Protected, HBA-Target: Protected, checksum conversion */
- SCSI_PROT_READ_CONVERT,
- SCSI_PROT_WRITE_CONVERT,
};
static inline void scsi_set_prot_op(struct scsi_cmnd *scmd, unsigned char op)
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index b62a097b3ecb..6e728b176904 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -798,9 +798,15 @@ static inline unsigned int scsi_host_get_prot(struct Scsi_Host *shost)
static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsigned int target_type)
{
switch (target_type) {
- case 1: return shost->prot_capabilities & SHOST_DIF_TYPE1_PROTECTION;
- case 2: return shost->prot_capabilities & SHOST_DIF_TYPE2_PROTECTION;
- case 3: return shost->prot_capabilities & SHOST_DIF_TYPE3_PROTECTION;
+ case 1:
+ if (shost->prot_capabilities & SHOST_DIF_TYPE1_PROTECTION)
+ return target_type;
+ case 2:
+ if (shost->prot_capabilities & SHOST_DIF_TYPE2_PROTECTION)
+ return target_type;
+ case 3:
+ if (shost->prot_capabilities & SHOST_DIF_TYPE3_PROTECTION)
+ return target_type;
}
return 0;
@@ -808,13 +814,14 @@ static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsign
static inline unsigned int scsi_host_dix_capable(struct Scsi_Host *shost, unsigned int target_type)
{
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
switch (target_type) {
case 0: return shost->prot_capabilities & SHOST_DIX_TYPE0_PROTECTION;
case 1: return shost->prot_capabilities & SHOST_DIX_TYPE1_PROTECTION;
case 2: return shost->prot_capabilities & SHOST_DIX_TYPE2_PROTECTION;
case 3: return shost->prot_capabilities & SHOST_DIX_TYPE3_PROTECTION;
}
-
+#endif
return 0;
}
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/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..0b1f917a53ba 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -413,6 +413,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/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/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/init/Kconfig b/init/Kconfig
index c7bac39d6c61..2e6e59f3e1b8 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -921,6 +921,11 @@ config HAVE_PERF_EVENTS
help
See tools/perf/design.txt for details.
+config PERF_USE_VMALLOC
+ bool
+ help
+ See tools/perf/design.txt for details
+
menu "Kernel Performance Events And Counters"
config PERF_EVENTS
@@ -976,6 +981,19 @@ config PERF_COUNTERS
Say N if unsure.
+config DEBUG_PERF_USE_VMALLOC
+ default n
+ bool "Debug: use vmalloc to back perf mmap() buffers"
+ depends on PERF_EVENTS && DEBUG_KERNEL
+ select PERF_USE_VMALLOC
+ help
+ Use vmalloc memory to back perf mmap() buffers.
+
+ Mostly useful for debugging the vmalloc code on platforms
+ that don't require it.
+
+ Say N if unsure.
+
endmenu
config VM_EVENT_COUNTERS
@@ -1041,6 +1059,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)"
@@ -1089,7 +1112,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..2bcd810ec471 100644
--- a/init/Makefile
+++ b/init/Makefile
@@ -16,11 +16,11 @@ 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
+clean-files := ../include/generated/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 +30,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/main.c b/init/main.c
index 7449819a4805..5988debfc505 100644
--- a/init/main.c
+++ b/init/main.c
@@ -778,7 +778,6 @@ static void __init do_initcalls(void)
*/
static void __init do_basic_setup(void)
{
- rcu_init_sched(); /* needed by module_init stage. */
init_workqueues();
cpuset_init_smp();
usermodehelper_init();
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/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/exit.c b/kernel/exit.c
index 5859f598c951..e61891f80123 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -991,8 +991,6 @@ NORET_TYPE void do_exit(long code)
tsk->mempolicy = NULL;
#endif
#ifdef CONFIG_FUTEX
- if (unlikely(!list_empty(&tsk->pi_state_list)))
- exit_pi_state_list(tsk);
if (unlikely(current->pi_state_cache))
kfree(current->pi_state_cache);
#endif
diff --git a/kernel/fork.c b/kernel/fork.c
index 266c6af6ef1b..4c20fff8c13a 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -570,12 +570,18 @@ void mm_release(struct task_struct *tsk, struct mm_struct *mm)
/* Get rid of any futexes when releasing the mm */
#ifdef CONFIG_FUTEX
- if (unlikely(tsk->robust_list))
+ if (unlikely(tsk->robust_list)) {
exit_robust_list(tsk);
+ tsk->robust_list = NULL;
+ }
#ifdef CONFIG_COMPAT
- if (unlikely(tsk->compat_robust_list))
+ if (unlikely(tsk->compat_robust_list)) {
compat_exit_robust_list(tsk);
+ tsk->compat_robust_list = NULL;
+ }
#endif
+ if (unlikely(!list_empty(&tsk->pi_state_list)))
+ exit_pi_state_list(tsk);
#endif
/* Get rid of any cached register state */
diff --git a/kernel/futex.c b/kernel/futex.c
index b911adceb2c4..4949d336d88d 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -916,8 +916,8 @@ retry:
hb1 = hash_futex(&key1);
hb2 = hash_futex(&key2);
- double_lock_hb(hb1, hb2);
retry_private:
+ double_lock_hb(hb1, hb2);
op_ret = futex_atomic_op_inuser(op, uaddr2);
if (unlikely(op_ret < 0)) {
@@ -2117,7 +2117,6 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
* Unqueue the futex_q and determine which it was.
*/
plist_del(&q->list, &q->list.plist);
- drop_futex_key_refs(&q->key);
if (timeout && !timeout->task)
ret = -ETIMEDOUT;
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 6d7020490f94..3e1c36e7998f 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -726,8 +726,6 @@ static int hrtimer_switch_to_hres(void)
/* "Retrigger" the interrupt to get things going */
retrigger_next_event(NULL);
local_irq_restore(flags);
- printk(KERN_DEBUG "Switched to high resolution mode on CPU %d\n",
- smp_processor_id());
return 1;
}
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index a81cf80554db..17c71bb565c6 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -11,6 +11,7 @@
*/
#include <linux/irq.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/random.h>
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/lockdep.c b/kernel/lockdep.c
index 3815ac1d58b2..9af56723c096 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -142,6 +142,11 @@ static inline struct lock_class *hlock_class(struct held_lock *hlock)
#ifdef CONFIG_LOCK_STAT
static DEFINE_PER_CPU(struct lock_class_stats[MAX_LOCKDEP_KEYS], lock_stats);
+static inline u64 lockstat_clock(void)
+{
+ return cpu_clock(smp_processor_id());
+}
+
static int lock_point(unsigned long points[], unsigned long ip)
{
int i;
@@ -158,7 +163,7 @@ static int lock_point(unsigned long points[], unsigned long ip)
return i;
}
-static void lock_time_inc(struct lock_time *lt, s64 time)
+static void lock_time_inc(struct lock_time *lt, u64 time)
{
if (time > lt->max)
lt->max = time;
@@ -234,12 +239,12 @@ static void put_lock_stats(struct lock_class_stats *stats)
static void lock_release_holdtime(struct held_lock *hlock)
{
struct lock_class_stats *stats;
- s64 holdtime;
+ u64 holdtime;
if (!lock_stat)
return;
- holdtime = sched_clock() - hlock->holdtime_stamp;
+ holdtime = lockstat_clock() - hlock->holdtime_stamp;
stats = get_lock_stats(hlock_class(hlock));
if (hlock->read)
@@ -2792,7 +2797,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
hlock->references = references;
#ifdef CONFIG_LOCK_STAT
hlock->waittime_stamp = 0;
- hlock->holdtime_stamp = sched_clock();
+ hlock->holdtime_stamp = lockstat_clock();
#endif
if (check == 2 && !mark_irqflags(curr, hlock))
@@ -3322,7 +3327,7 @@ found_it:
if (hlock->instance != lock)
return;
- hlock->waittime_stamp = sched_clock();
+ hlock->waittime_stamp = lockstat_clock();
contention_point = lock_point(hlock_class(hlock)->contention_point, ip);
contending_point = lock_point(hlock_class(hlock)->contending_point,
@@ -3345,8 +3350,7 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip)
struct held_lock *hlock, *prev_hlock;
struct lock_class_stats *stats;
unsigned int depth;
- u64 now;
- s64 waittime = 0;
+ u64 now, waittime = 0;
int i, cpu;
depth = curr->lockdep_depth;
@@ -3374,7 +3378,7 @@ found_it:
cpu = smp_processor_id();
if (hlock->waittime_stamp) {
- now = sched_clock();
+ now = lockstat_clock();
waittime = now - hlock->waittime_stamp;
hlock->holdtime_stamp = now;
}
diff --git a/kernel/mutex-debug.c b/kernel/mutex-debug.c
index 50d022e5a560..ec815a960b5d 100644
--- a/kernel/mutex-debug.c
+++ b/kernel/mutex-debug.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/poison.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
diff --git a/kernel/panic.c b/kernel/panic.c
index bcdef26e3332..96b45d0b4ba5 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -90,6 +90,8 @@ NORET_TYPE void panic(const char * fmt, ...)
atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
+ bust_spinlocks(0);
+
if (!panic_blink)
panic_blink = no_blink;
@@ -136,7 +138,6 @@ NORET_TYPE void panic(const char * fmt, ...)
mdelay(1);
i++;
}
- bust_spinlocks(0);
}
EXPORT_SYMBOL(panic);
diff --git a/kernel/perf_event.c b/kernel/perf_event.c
index 0f86feb6db0c..9d0b5c665883 100644
--- a/kernel/perf_event.c
+++ b/kernel/perf_event.c
@@ -20,6 +20,7 @@
#include <linux/percpu.h>
#include <linux/ptrace.h>
#include <linux/vmstat.h>
+#include <linux/vmalloc.h>
#include <linux/hardirq.h>
#include <linux/rculist.h>
#include <linux/uaccess.h>
@@ -1030,14 +1031,10 @@ void __perf_event_sched_out(struct perf_event_context *ctx,
update_context_time(ctx);
perf_disable();
- if (ctx->nr_active) {
- list_for_each_entry(event, &ctx->group_list, group_entry) {
- if (event != event->group_leader)
- event_sched_out(event, cpuctx, ctx);
- else
- group_sched_out(event, cpuctx, ctx);
- }
- }
+ if (ctx->nr_active)
+ list_for_each_entry(event, &ctx->group_list, group_entry)
+ group_sched_out(event, cpuctx, ctx);
+
perf_enable();
out:
spin_unlock(&ctx->lock);
@@ -1258,12 +1255,8 @@ __perf_event_sched_in(struct perf_event_context *ctx,
if (event->cpu != -1 && event->cpu != cpu)
continue;
- if (event != event->group_leader)
- event_sched_in(event, cpuctx, ctx, cpu);
- else {
- if (group_can_go_on(event, cpuctx, 1))
- group_sched_in(event, cpuctx, ctx, cpu);
- }
+ if (group_can_go_on(event, cpuctx, 1))
+ group_sched_in(event, cpuctx, ctx, cpu);
/*
* If this pinned group hasn't been scheduled,
@@ -1291,15 +1284,9 @@ __perf_event_sched_in(struct perf_event_context *ctx,
if (event->cpu != -1 && event->cpu != cpu)
continue;
- if (event != event->group_leader) {
- if (event_sched_in(event, cpuctx, ctx, cpu))
+ if (group_can_go_on(event, cpuctx, can_add_hw))
+ if (group_sched_in(event, cpuctx, ctx, cpu))
can_add_hw = 0;
- } else {
- if (group_can_go_on(event, cpuctx, can_add_hw)) {
- if (group_sched_in(event, cpuctx, ctx, cpu))
- can_add_hw = 0;
- }
- }
}
perf_enable();
out:
@@ -2105,49 +2092,31 @@ unlock:
rcu_read_unlock();
}
-static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+static unsigned long perf_data_size(struct perf_mmap_data *data)
{
- struct perf_event *event = vma->vm_file->private_data;
- struct perf_mmap_data *data;
- int ret = VM_FAULT_SIGBUS;
-
- if (vmf->flags & FAULT_FLAG_MKWRITE) {
- if (vmf->pgoff == 0)
- ret = 0;
- return ret;
- }
-
- rcu_read_lock();
- data = rcu_dereference(event->data);
- if (!data)
- goto unlock;
-
- if (vmf->pgoff == 0) {
- vmf->page = virt_to_page(data->user_page);
- } else {
- int nr = vmf->pgoff - 1;
-
- if ((unsigned)nr > data->nr_pages)
- goto unlock;
+ return data->nr_pages << (PAGE_SHIFT + data->data_order);
+}
- if (vmf->flags & FAULT_FLAG_WRITE)
- goto unlock;
+#ifndef CONFIG_PERF_USE_VMALLOC
- vmf->page = virt_to_page(data->data_pages[nr]);
- }
+/*
+ * Back perf_mmap() with regular GFP_KERNEL-0 pages.
+ */
- get_page(vmf->page);
- vmf->page->mapping = vma->vm_file->f_mapping;
- vmf->page->index = vmf->pgoff;
+static struct page *
+perf_mmap_to_page(struct perf_mmap_data *data, unsigned long pgoff)
+{
+ if (pgoff > data->nr_pages)
+ return NULL;
- ret = 0;
-unlock:
- rcu_read_unlock();
+ if (pgoff == 0)
+ return virt_to_page(data->user_page);
- return ret;
+ return virt_to_page(data->data_pages[pgoff - 1]);
}
-static int perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
+static struct perf_mmap_data *
+perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
{
struct perf_mmap_data *data;
unsigned long size;
@@ -2172,19 +2141,10 @@ static int perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
goto fail_data_pages;
}
+ data->data_order = 0;
data->nr_pages = nr_pages;
- atomic_set(&data->lock, -1);
-
- if (event->attr.watermark) {
- data->watermark = min_t(long, PAGE_SIZE * nr_pages,
- event->attr.wakeup_watermark);
- }
- if (!data->watermark)
- data->watermark = max(PAGE_SIZE, PAGE_SIZE * nr_pages / 4);
- rcu_assign_pointer(event->data, data);
-
- return 0;
+ return data;
fail_data_pages:
for (i--; i >= 0; i--)
@@ -2196,7 +2156,7 @@ fail_user_page:
kfree(data);
fail:
- return -ENOMEM;
+ return NULL;
}
static void perf_mmap_free_page(unsigned long addr)
@@ -2207,28 +2167,169 @@ static void perf_mmap_free_page(unsigned long addr)
__free_page(page);
}
-static void __perf_mmap_data_free(struct rcu_head *rcu_head)
+static void perf_mmap_data_free(struct perf_mmap_data *data)
{
- struct perf_mmap_data *data;
int i;
- data = container_of(rcu_head, struct perf_mmap_data, rcu_head);
-
perf_mmap_free_page((unsigned long)data->user_page);
for (i = 0; i < data->nr_pages; i++)
perf_mmap_free_page((unsigned long)data->data_pages[i]);
+}
+
+#else
+
+/*
+ * Back perf_mmap() with vmalloc memory.
+ *
+ * Required for architectures that have d-cache aliasing issues.
+ */
+
+static struct page *
+perf_mmap_to_page(struct perf_mmap_data *data, unsigned long pgoff)
+{
+ if (pgoff > (1UL << data->data_order))
+ return NULL;
+
+ return vmalloc_to_page((void *)data->user_page + pgoff * PAGE_SIZE);
+}
+
+static void perf_mmap_unmark_page(void *addr)
+{
+ struct page *page = vmalloc_to_page(addr);
+
+ page->mapping = NULL;
+}
+
+static void perf_mmap_data_free_work(struct work_struct *work)
+{
+ struct perf_mmap_data *data;
+ void *base;
+ int i, nr;
+
+ data = container_of(work, struct perf_mmap_data, work);
+ nr = 1 << data->data_order;
+
+ base = data->user_page;
+ for (i = 0; i < nr + 1; i++)
+ perf_mmap_unmark_page(base + (i * PAGE_SIZE));
+
+ vfree(base);
+}
+static void perf_mmap_data_free(struct perf_mmap_data *data)
+{
+ schedule_work(&data->work);
+}
+
+static struct perf_mmap_data *
+perf_mmap_data_alloc(struct perf_event *event, int nr_pages)
+{
+ struct perf_mmap_data *data;
+ unsigned long size;
+ void *all_buf;
+
+ WARN_ON(atomic_read(&event->mmap_count));
+
+ size = sizeof(struct perf_mmap_data);
+ size += sizeof(void *);
+
+ data = kzalloc(size, GFP_KERNEL);
+ if (!data)
+ goto fail;
+
+ INIT_WORK(&data->work, perf_mmap_data_free_work);
+
+ all_buf = vmalloc_user((nr_pages + 1) * PAGE_SIZE);
+ if (!all_buf)
+ goto fail_all_buf;
+
+ data->user_page = all_buf;
+ data->data_pages[0] = all_buf + PAGE_SIZE;
+ data->data_order = ilog2(nr_pages);
+ data->nr_pages = 1;
+
+ return data;
+
+fail_all_buf:
+ kfree(data);
+
+fail:
+ return NULL;
+}
+
+#endif
+
+static int perf_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct perf_event *event = vma->vm_file->private_data;
+ struct perf_mmap_data *data;
+ int ret = VM_FAULT_SIGBUS;
+
+ if (vmf->flags & FAULT_FLAG_MKWRITE) {
+ if (vmf->pgoff == 0)
+ ret = 0;
+ return ret;
+ }
+
+ rcu_read_lock();
+ data = rcu_dereference(event->data);
+ if (!data)
+ goto unlock;
+
+ if (vmf->pgoff && (vmf->flags & FAULT_FLAG_WRITE))
+ goto unlock;
+
+ vmf->page = perf_mmap_to_page(data, vmf->pgoff);
+ if (!vmf->page)
+ goto unlock;
+
+ get_page(vmf->page);
+ vmf->page->mapping = vma->vm_file->f_mapping;
+ vmf->page->index = vmf->pgoff;
+
+ ret = 0;
+unlock:
+ rcu_read_unlock();
+
+ return ret;
+}
+
+static void
+perf_mmap_data_init(struct perf_event *event, struct perf_mmap_data *data)
+{
+ long max_size = perf_data_size(data);
+
+ atomic_set(&data->lock, -1);
+
+ if (event->attr.watermark) {
+ data->watermark = min_t(long, max_size,
+ event->attr.wakeup_watermark);
+ }
+
+ if (!data->watermark)
+ data->watermark = max_t(long, PAGE_SIZE, max_size / 2);
+
+
+ rcu_assign_pointer(event->data, data);
+}
+
+static void perf_mmap_data_free_rcu(struct rcu_head *rcu_head)
+{
+ struct perf_mmap_data *data;
+
+ data = container_of(rcu_head, struct perf_mmap_data, rcu_head);
+ perf_mmap_data_free(data);
kfree(data);
}
-static void perf_mmap_data_free(struct perf_event *event)
+static void perf_mmap_data_release(struct perf_event *event)
{
struct perf_mmap_data *data = event->data;
WARN_ON(atomic_read(&event->mmap_count));
rcu_assign_pointer(event->data, NULL);
- call_rcu(&data->rcu_head, __perf_mmap_data_free);
+ call_rcu(&data->rcu_head, perf_mmap_data_free_rcu);
}
static void perf_mmap_open(struct vm_area_struct *vma)
@@ -2244,11 +2345,12 @@ static void perf_mmap_close(struct vm_area_struct *vma)
WARN_ON_ONCE(event->ctx->parent_ctx);
if (atomic_dec_and_mutex_lock(&event->mmap_count, &event->mmap_mutex)) {
+ unsigned long size = perf_data_size(event->data);
struct user_struct *user = current_user();
- atomic_long_sub(event->data->nr_pages + 1, &user->locked_vm);
+ atomic_long_sub((size >> PAGE_SHIFT) + 1, &user->locked_vm);
vma->vm_mm->locked_vm -= event->data->nr_locked;
- perf_mmap_data_free(event);
+ perf_mmap_data_release(event);
mutex_unlock(&event->mmap_mutex);
}
}
@@ -2266,6 +2368,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
unsigned long user_locked, user_lock_limit;
struct user_struct *user = current_user();
unsigned long locked, lock_limit;
+ struct perf_mmap_data *data;
unsigned long vma_size;
unsigned long nr_pages;
long user_extra, extra;
@@ -2328,10 +2431,15 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
}
WARN_ON(event->data);
- ret = perf_mmap_data_alloc(event, nr_pages);
- if (ret)
+
+ data = perf_mmap_data_alloc(event, nr_pages);
+ ret = -ENOMEM;
+ if (!data)
goto unlock;
+ ret = 0;
+ perf_mmap_data_init(event, data);
+
atomic_set(&event->mmap_count, 1);
atomic_long_add(user_extra, &user->locked_vm);
vma->vm_mm->locked_vm += extra;
@@ -2519,7 +2627,7 @@ static bool perf_output_space(struct perf_mmap_data *data, unsigned long tail,
if (!data->writable)
return true;
- mask = (data->nr_pages << PAGE_SHIFT) - 1;
+ mask = perf_data_size(data) - 1;
offset = (offset - tail) & mask;
head = (head - tail) & mask;
@@ -2624,7 +2732,7 @@ void perf_output_copy(struct perf_output_handle *handle,
const void *buf, unsigned int len)
{
unsigned int pages_mask;
- unsigned int offset;
+ unsigned long offset;
unsigned int size;
void **pages;
@@ -2633,12 +2741,14 @@ void perf_output_copy(struct perf_output_handle *handle,
pages = handle->data->data_pages;
do {
- unsigned int page_offset;
+ unsigned long page_offset;
+ unsigned long page_size;
int nr;
nr = (offset >> PAGE_SHIFT) & pages_mask;
- page_offset = offset & (PAGE_SIZE - 1);
- size = min_t(unsigned int, PAGE_SIZE - page_offset, len);
+ page_size = 1UL << (handle->data->data_order + PAGE_SHIFT);
+ page_offset = offset & (page_size - 1);
+ size = min_t(unsigned int, page_size - page_offset, len);
memcpy(pages[nr] + page_offset, buf, size);
@@ -4781,9 +4891,7 @@ int perf_event_init_task(struct task_struct *child)
* We dont have to disable NMIs - we are only looking at
* the list, not manipulating it:
*/
- list_for_each_entry_rcu(event, &parent_ctx->event_list, event_entry) {
- if (event != event->group_leader)
- continue;
+ list_for_each_entry(event, &parent_ctx->group_list, group_entry) {
if (!event->attr.inherit) {
inherited_all = 0;
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 37ac45483082..400183346ad2 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -46,22 +46,15 @@
#include <linux/module.h>
#include <linux/kernel_stat.h>
-enum rcu_barrier {
- RCU_BARRIER_STD,
- RCU_BARRIER_BH,
- RCU_BARRIER_SCHED,
-};
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+static struct lock_class_key rcu_lock_key;
+struct lockdep_map rcu_lock_map =
+ STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key);
+EXPORT_SYMBOL_GPL(rcu_lock_map);
+#endif
-static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL};
-static atomic_t rcu_barrier_cpu_count;
-static DEFINE_MUTEX(rcu_barrier_mutex);
-static struct completion rcu_barrier_completion;
int rcu_scheduler_active __read_mostly;
-static atomic_t rcu_migrate_type_count = ATOMIC_INIT(0);
-static struct rcu_head rcu_migrate_head[3];
-static DECLARE_WAIT_QUEUE_HEAD(rcu_migrate_wq);
-
/*
* Awaken the corresponding synchronize_rcu() instance now that a
* grace period has elapsed.
@@ -164,129 +157,10 @@ void synchronize_rcu_bh(void)
}
EXPORT_SYMBOL_GPL(synchronize_rcu_bh);
-static void rcu_barrier_callback(struct rcu_head *notused)
-{
- if (atomic_dec_and_test(&rcu_barrier_cpu_count))
- complete(&rcu_barrier_completion);
-}
-
-/*
- * Called with preemption disabled, and from cross-cpu IRQ context.
- */
-static void rcu_barrier_func(void *type)
-{
- int cpu = smp_processor_id();
- struct rcu_head *head = &per_cpu(rcu_barrier_head, cpu);
-
- atomic_inc(&rcu_barrier_cpu_count);
- switch ((enum rcu_barrier)type) {
- case RCU_BARRIER_STD:
- call_rcu(head, rcu_barrier_callback);
- break;
- case RCU_BARRIER_BH:
- call_rcu_bh(head, rcu_barrier_callback);
- break;
- case RCU_BARRIER_SCHED:
- call_rcu_sched(head, rcu_barrier_callback);
- break;
- }
-}
-
-static inline void wait_migrated_callbacks(void)
-{
- wait_event(rcu_migrate_wq, !atomic_read(&rcu_migrate_type_count));
- smp_mb(); /* In case we didn't sleep. */
-}
-
-/*
- * Orchestrate the specified type of RCU barrier, waiting for all
- * RCU callbacks of the specified type to complete.
- */
-static void _rcu_barrier(enum rcu_barrier type)
-{
- BUG_ON(in_interrupt());
- /* Take cpucontrol mutex to protect against CPU hotplug */
- mutex_lock(&rcu_barrier_mutex);
- init_completion(&rcu_barrier_completion);
- /*
- * Initialize rcu_barrier_cpu_count to 1, then invoke
- * rcu_barrier_func() on each CPU, so that each CPU also has
- * incremented rcu_barrier_cpu_count. Only then is it safe to
- * decrement rcu_barrier_cpu_count -- otherwise the first CPU
- * might complete its grace period before all of the other CPUs
- * did their increment, causing this function to return too
- * early.
- */
- atomic_set(&rcu_barrier_cpu_count, 1);
- on_each_cpu(rcu_barrier_func, (void *)type, 1);
- if (atomic_dec_and_test(&rcu_barrier_cpu_count))
- complete(&rcu_barrier_completion);
- wait_for_completion(&rcu_barrier_completion);
- mutex_unlock(&rcu_barrier_mutex);
- wait_migrated_callbacks();
-}
-
-/**
- * rcu_barrier - Wait until all in-flight call_rcu() callbacks complete.
- */
-void rcu_barrier(void)
-{
- _rcu_barrier(RCU_BARRIER_STD);
-}
-EXPORT_SYMBOL_GPL(rcu_barrier);
-
-/**
- * rcu_barrier_bh - Wait until all in-flight call_rcu_bh() callbacks complete.
- */
-void rcu_barrier_bh(void)
-{
- _rcu_barrier(RCU_BARRIER_BH);
-}
-EXPORT_SYMBOL_GPL(rcu_barrier_bh);
-
-/**
- * rcu_barrier_sched - Wait for in-flight call_rcu_sched() callbacks.
- */
-void rcu_barrier_sched(void)
-{
- _rcu_barrier(RCU_BARRIER_SCHED);
-}
-EXPORT_SYMBOL_GPL(rcu_barrier_sched);
-
-static void rcu_migrate_callback(struct rcu_head *notused)
-{
- if (atomic_dec_and_test(&rcu_migrate_type_count))
- wake_up(&rcu_migrate_wq);
-}
-
-extern int rcu_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu);
-
static int __cpuinit rcu_barrier_cpu_hotplug(struct notifier_block *self,
unsigned long action, void *hcpu)
{
- rcu_cpu_notify(self, action, hcpu);
- if (action == CPU_DYING) {
- /*
- * preempt_disable() in on_each_cpu() prevents stop_machine(),
- * so when "on_each_cpu(rcu_barrier_func, (void *)type, 1);"
- * returns, all online cpus have queued rcu_barrier_func(),
- * and the dead cpu(if it exist) queues rcu_migrate_callback()s.
- *
- * These callbacks ensure _rcu_barrier() waits for all
- * RCU callbacks of the specified type to complete.
- */
- atomic_set(&rcu_migrate_type_count, 3);
- call_rcu_bh(rcu_migrate_head, rcu_migrate_callback);
- call_rcu_sched(rcu_migrate_head + 1, rcu_migrate_callback);
- call_rcu(rcu_migrate_head + 2, rcu_migrate_callback);
- } else if (action == CPU_DOWN_PREPARE) {
- /* Don't need to wait until next removal operation. */
- /* rcu_migrate_head is protected by cpu_add_remove_lock */
- wait_migrated_callbacks();
- }
-
- return NOTIFY_OK;
+ return rcu_cpu_notify(self, action, hcpu);
}
void __init rcu_init(void)
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 233768f21f97..697c0a0229d4 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -606,8 +606,6 @@ static struct rcu_torture_ops sched_ops_sync = {
.name = "sched_sync"
};
-extern int rcu_expedited_torture_stats(char *page);
-
static struct rcu_torture_ops sched_expedited_ops = {
.init = rcu_sync_torture_init,
.cleanup = NULL,
@@ -650,7 +648,7 @@ rcu_torture_writer(void *arg)
old_rp = rcu_torture_current;
rp->rtort_mbtest = 1;
rcu_assign_pointer(rcu_torture_current, rp);
- smp_wmb();
+ smp_wmb(); /* Mods to old_rp must follow rcu_assign_pointer() */
if (old_rp) {
i = old_rp->rtort_pipe_count;
if (i > RCU_TORTURE_PIPE_LEN)
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index 52b06f6e158c..705f02ac7433 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -49,13 +49,6 @@
#include "rcutree.h"
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-static struct lock_class_key rcu_lock_key;
-struct lockdep_map rcu_lock_map =
- STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key);
-EXPORT_SYMBOL_GPL(rcu_lock_map);
-#endif
-
/* Data structures. */
#define RCU_STATE_INITIALIZER(name) { \
@@ -70,6 +63,9 @@ EXPORT_SYMBOL_GPL(rcu_lock_map);
.gpnum = -300, \
.completed = -300, \
.onofflock = __SPIN_LOCK_UNLOCKED(&name.onofflock), \
+ .orphan_cbs_list = NULL, \
+ .orphan_cbs_tail = &name.orphan_cbs_list, \
+ .orphan_qlen = 0, \
.fqslock = __SPIN_LOCK_UNLOCKED(&name.fqslock), \
.n_force_qs = 0, \
.n_force_qs_ngp = 0, \
@@ -81,24 +77,16 @@ DEFINE_PER_CPU(struct rcu_data, rcu_sched_data);
struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh_state);
DEFINE_PER_CPU(struct rcu_data, rcu_bh_data);
-extern long rcu_batches_completed_sched(void);
-static struct rcu_node *rcu_get_root(struct rcu_state *rsp);
-static void cpu_quiet_msk(unsigned long mask, struct rcu_state *rsp,
- struct rcu_node *rnp, unsigned long flags);
-static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags);
-#ifdef CONFIG_HOTPLUG_CPU
-static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp);
-#endif /* #ifdef CONFIG_HOTPLUG_CPU */
-static void __rcu_process_callbacks(struct rcu_state *rsp,
- struct rcu_data *rdp);
-static void __call_rcu(struct rcu_head *head,
- void (*func)(struct rcu_head *rcu),
- struct rcu_state *rsp);
-static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp);
-static void __cpuinit rcu_init_percpu_data(int cpu, struct rcu_state *rsp,
- int preemptable);
-#include "rcutree_plugin.h"
+/*
+ * Return true if an RCU grace period is in progress. The ACCESS_ONCE()s
+ * permit this function to be invoked without holding the root rcu_node
+ * structure's ->lock, but of course results can be subject to change.
+ */
+static int rcu_gp_in_progress(struct rcu_state *rsp)
+{
+ return ACCESS_ONCE(rsp->completed) != ACCESS_ONCE(rsp->gpnum);
+}
/*
* Note a quiescent state. Because we do not need to know
@@ -137,6 +125,10 @@ static int blimit = 10; /* Maximum callbacks per softirq. */
static int qhimark = 10000; /* If this many pending, ignore blimit. */
static int qlowmark = 100; /* Once only this many pending, use blimit. */
+module_param(blimit, int, 0);
+module_param(qhimark, int, 0);
+module_param(qlowmark, int, 0);
+
static void force_quiescent_state(struct rcu_state *rsp, int relaxed);
static int rcu_pending(int cpu);
@@ -173,9 +165,7 @@ cpu_has_callbacks_ready_to_invoke(struct rcu_data *rdp)
static int
cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
{
- /* ACCESS_ONCE() because we are accessing outside of lock. */
- return *rdp->nxttail[RCU_DONE_TAIL] &&
- ACCESS_ONCE(rsp->completed) == ACCESS_ONCE(rsp->gpnum);
+ return *rdp->nxttail[RCU_DONE_TAIL] && !rcu_gp_in_progress(rsp);
}
/*
@@ -369,7 +359,7 @@ static long dyntick_recall_completed(struct rcu_state *rsp)
/*
* Snapshot the specified CPU's dynticks counter so that we can later
* credit them with an implicit quiescent state. Return 1 if this CPU
- * is already in a quiescent state courtesy of dynticks idle mode.
+ * is in dynticks idle mode, which is an extended quiescent state.
*/
static int dyntick_save_progress_counter(struct rcu_data *rdp)
{
@@ -475,30 +465,34 @@ static void print_other_cpu_stall(struct rcu_state *rsp)
long delta;
unsigned long flags;
struct rcu_node *rnp = rcu_get_root(rsp);
- struct rcu_node *rnp_cur = rsp->level[NUM_RCU_LVLS - 1];
- struct rcu_node *rnp_end = &rsp->node[NUM_RCU_NODES];
/* Only let one CPU complain about others per time interval. */
spin_lock_irqsave(&rnp->lock, flags);
delta = jiffies - rsp->jiffies_stall;
- if (delta < RCU_STALL_RAT_DELAY || rsp->gpnum == rsp->completed) {
+ if (delta < RCU_STALL_RAT_DELAY || !rcu_gp_in_progress(rsp)) {
spin_unlock_irqrestore(&rnp->lock, flags);
return;
}
rsp->jiffies_stall = jiffies + RCU_SECONDS_TILL_STALL_RECHECK;
+
+ /*
+ * Now rat on any tasks that got kicked up to the root rcu_node
+ * due to CPU offlining.
+ */
+ rcu_print_task_stall(rnp);
spin_unlock_irqrestore(&rnp->lock, flags);
/* OK, time to rat on our buddy... */
printk(KERN_ERR "INFO: RCU detected CPU stalls:");
- for (; rnp_cur < rnp_end; rnp_cur++) {
+ rcu_for_each_leaf_node(rsp, rnp) {
rcu_print_task_stall(rnp);
- if (rnp_cur->qsmask == 0)
+ if (rnp->qsmask == 0)
continue;
- for (cpu = 0; cpu <= rnp_cur->grphi - rnp_cur->grplo; cpu++)
- if (rnp_cur->qsmask & (1UL << cpu))
- printk(" %d", rnp_cur->grplo + cpu);
+ for (cpu = 0; cpu <= rnp->grphi - rnp->grplo; cpu++)
+ if (rnp->qsmask & (1UL << cpu))
+ printk(" %d", rnp->grplo + cpu);
}
printk(" (detected by %d, t=%ld jiffies)\n",
smp_processor_id(), (long)(jiffies - rsp->gp_start));
@@ -537,8 +531,7 @@ static void check_cpu_stall(struct rcu_state *rsp, struct rcu_data *rdp)
/* We haven't checked in, so go dump stack. */
print_cpu_stall(rsp);
- } else if (rsp->gpnum != rsp->completed &&
- delta >= RCU_STALL_RAT_DELAY) {
+ } else if (rcu_gp_in_progress(rsp) && delta >= RCU_STALL_RAT_DELAY) {
/* They had two time units to dump stack, so complain. */
print_other_cpu_stall(rsp);
@@ -617,9 +610,15 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
note_new_gpnum(rsp, rdp);
/*
- * Because we are first, we know that all our callbacks will
- * be covered by this upcoming grace period, even the ones
- * that were registered arbitrarily recently.
+ * Because this CPU just now started the new grace period, we know
+ * that all of its callbacks will be covered by this upcoming grace
+ * period, even the ones that were registered arbitrarily recently.
+ * Therefore, advance all outstanding callbacks to RCU_WAIT_TAIL.
+ *
+ * Other CPUs cannot be sure exactly when the grace period started.
+ * Therefore, their recently registered callbacks must pass through
+ * an additional RCU_NEXT_READY stage, so that they will be handled
+ * by the next RCU grace period.
*/
rdp->nxttail[RCU_NEXT_READY_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
rdp->nxttail[RCU_WAIT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
@@ -657,7 +656,7 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
* one corresponding to this CPU, due to the fact that we have
* irqs disabled.
*/
- for (rnp = &rsp->node[0]; rnp < &rsp->node[NUM_RCU_NODES]; rnp++) {
+ rcu_for_each_node_breadth_first(rsp, rnp) {
spin_lock(&rnp->lock); /* irqs already disabled. */
rcu_preempt_check_blocked_tasks(rnp);
rnp->qsmask = rnp->qsmaskinit;
@@ -703,9 +702,9 @@ rcu_process_gp_end(struct rcu_state *rsp, struct rcu_data *rdp)
* hold rnp->lock, as required by rcu_start_gp(), which will release it.
*/
static void cpu_quiet_msk_finish(struct rcu_state *rsp, unsigned long flags)
- __releases(rnp->lock)
+ __releases(rcu_get_root(rsp)->lock)
{
- WARN_ON_ONCE(rsp->completed == rsp->gpnum);
+ WARN_ON_ONCE(!rcu_gp_in_progress(rsp));
rsp->completed = rsp->gpnum;
rcu_process_gp_end(rsp, rsp->rda[smp_processor_id()]);
rcu_start_gp(rsp, flags); /* releases root node's rnp->lock. */
@@ -842,17 +841,63 @@ rcu_check_quiescent_state(struct rcu_state *rsp, struct rcu_data *rdp)
#ifdef CONFIG_HOTPLUG_CPU
/*
+ * Move a dying CPU's RCU callbacks to the ->orphan_cbs_list for the
+ * specified flavor of RCU. The callbacks will be adopted by the next
+ * _rcu_barrier() invocation or by the CPU_DEAD notifier, whichever
+ * comes first. Because this is invoked from the CPU_DYING notifier,
+ * irqs are already disabled.
+ */
+static void rcu_send_cbs_to_orphanage(struct rcu_state *rsp)
+{
+ int i;
+ struct rcu_data *rdp = rsp->rda[smp_processor_id()];
+
+ if (rdp->nxtlist == NULL)
+ return; /* irqs disabled, so comparison is stable. */
+ spin_lock(&rsp->onofflock); /* irqs already disabled. */
+ *rsp->orphan_cbs_tail = rdp->nxtlist;
+ rsp->orphan_cbs_tail = rdp->nxttail[RCU_NEXT_TAIL];
+ rdp->nxtlist = NULL;
+ for (i = 0; i < RCU_NEXT_SIZE; i++)
+ rdp->nxttail[i] = &rdp->nxtlist;
+ rsp->orphan_qlen += rdp->qlen;
+ rdp->qlen = 0;
+ spin_unlock(&rsp->onofflock); /* irqs remain disabled. */
+}
+
+/*
+ * Adopt previously orphaned RCU callbacks.
+ */
+static void rcu_adopt_orphan_cbs(struct rcu_state *rsp)
+{
+ unsigned long flags;
+ struct rcu_data *rdp;
+
+ spin_lock_irqsave(&rsp->onofflock, flags);
+ rdp = rsp->rda[smp_processor_id()];
+ if (rsp->orphan_cbs_list == NULL) {
+ spin_unlock_irqrestore(&rsp->onofflock, flags);
+ return;
+ }
+ *rdp->nxttail[RCU_NEXT_TAIL] = rsp->orphan_cbs_list;
+ rdp->nxttail[RCU_NEXT_TAIL] = rsp->orphan_cbs_tail;
+ rdp->qlen += rsp->orphan_qlen;
+ rsp->orphan_cbs_list = NULL;
+ rsp->orphan_cbs_tail = &rsp->orphan_cbs_list;
+ rsp->orphan_qlen = 0;
+ spin_unlock_irqrestore(&rsp->onofflock, flags);
+}
+
+/*
* Remove the outgoing CPU from the bitmasks in the rcu_node hierarchy
* and move all callbacks from the outgoing CPU to the current one.
*/
static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
{
- int i;
unsigned long flags;
long lastcomp;
unsigned long mask;
struct rcu_data *rdp = rsp->rda[cpu];
- struct rcu_data *rdp_me;
struct rcu_node *rnp;
/* Exclude any attempts to start a new grace period. */
@@ -875,32 +920,9 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)
} while (rnp != NULL);
lastcomp = rsp->completed;
- spin_unlock(&rsp->onofflock); /* irqs remain disabled. */
+ spin_unlock_irqrestore(&rsp->onofflock, flags);
- /*
- * Move callbacks from the outgoing CPU to the running CPU.
- * Note that the outgoing CPU is now quiscent, so it is now
- * (uncharacteristically) safe to access its rcu_data structure.
- * Note also that we must carefully retain the order of the
- * outgoing CPU's callbacks in order for rcu_barrier() to work
- * correctly. Finally, note that we start all the callbacks
- * afresh, even those that have passed through a grace period
- * and are therefore ready to invoke. The theory is that hotplug
- * events are rare, and that if they are frequent enough to
- * indefinitely delay callbacks, you have far worse things to
- * be worrying about.
- */
- rdp_me = rsp->rda[smp_processor_id()];
- if (rdp->nxtlist != NULL) {
- *rdp_me->nxttail[RCU_NEXT_TAIL] = rdp->nxtlist;
- rdp_me->nxttail[RCU_NEXT_TAIL] = rdp->nxttail[RCU_NEXT_TAIL];
- rdp->nxtlist = NULL;
- for (i = 0; i < RCU_NEXT_SIZE; i++)
- rdp->nxttail[i] = &rdp->nxtlist;
- rdp_me->qlen += rdp->qlen;
- rdp->qlen = 0;
- }
- local_irq_restore(flags);
+ rcu_adopt_orphan_cbs(rsp);
}
/*
@@ -918,6 +940,14 @@ static void rcu_offline_cpu(int cpu)
#else /* #ifdef CONFIG_HOTPLUG_CPU */
+static void rcu_send_cbs_to_orphanage(struct rcu_state *rsp)
+{
+}
+
+static void rcu_adopt_orphan_cbs(struct rcu_state *rsp)
+{
+}
+
static void rcu_offline_cpu(int cpu)
{
}
@@ -1050,33 +1080,32 @@ static int rcu_process_dyntick(struct rcu_state *rsp, long lastcomp,
int cpu;
unsigned long flags;
unsigned long mask;
- struct rcu_node *rnp_cur = rsp->level[NUM_RCU_LVLS - 1];
- struct rcu_node *rnp_end = &rsp->node[NUM_RCU_NODES];
+ struct rcu_node *rnp;
- for (; rnp_cur < rnp_end; rnp_cur++) {
+ rcu_for_each_leaf_node(rsp, rnp) {
mask = 0;
- spin_lock_irqsave(&rnp_cur->lock, flags);
+ spin_lock_irqsave(&rnp->lock, flags);
if (rsp->completed != lastcomp) {
- spin_unlock_irqrestore(&rnp_cur->lock, flags);
+ spin_unlock_irqrestore(&rnp->lock, flags);
return 1;
}
- if (rnp_cur->qsmask == 0) {
- spin_unlock_irqrestore(&rnp_cur->lock, flags);
+ if (rnp->qsmask == 0) {
+ spin_unlock_irqrestore(&rnp->lock, flags);
continue;
}
- cpu = rnp_cur->grplo;
+ cpu = rnp->grplo;
bit = 1;
- for (; cpu <= rnp_cur->grphi; cpu++, bit <<= 1) {
- if ((rnp_cur->qsmask & bit) != 0 && f(rsp->rda[cpu]))
+ for (; cpu <= rnp->grphi; cpu++, bit <<= 1) {
+ if ((rnp->qsmask & bit) != 0 && f(rsp->rda[cpu]))
mask |= bit;
}
if (mask != 0 && rsp->completed == lastcomp) {
- /* cpu_quiet_msk() releases rnp_cur->lock. */
- cpu_quiet_msk(mask, rsp, rnp_cur, flags);
+ /* cpu_quiet_msk() releases rnp->lock. */
+ cpu_quiet_msk(mask, rsp, rnp, flags);
continue;
}
- spin_unlock_irqrestore(&rnp_cur->lock, flags);
+ spin_unlock_irqrestore(&rnp->lock, flags);
}
return 0;
}
@@ -1092,7 +1121,7 @@ static void force_quiescent_state(struct rcu_state *rsp, int relaxed)
struct rcu_node *rnp = rcu_get_root(rsp);
u8 signaled;
- if (ACCESS_ONCE(rsp->completed) == ACCESS_ONCE(rsp->gpnum))
+ if (!rcu_gp_in_progress(rsp))
return; /* No grace period in progress, nothing to force. */
if (!spin_trylock_irqsave(&rsp->fqslock, flags)) {
rsp->n_force_qs_lh++; /* Inexact, can lose counts. Tough! */
@@ -1251,7 +1280,7 @@ __call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu),
rdp->nxttail[RCU_NEXT_TAIL] = &head->next;
/* Start a new grace period if one not already started. */
- if (ACCESS_ONCE(rsp->completed) == ACCESS_ONCE(rsp->gpnum)) {
+ if (!rcu_gp_in_progress(rsp)) {
unsigned long nestflag;
struct rcu_node *rnp_root = rcu_get_root(rsp);
@@ -1331,7 +1360,7 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
}
/* Has an RCU GP gone long enough to send resched IPIs &c? */
- if (ACCESS_ONCE(rsp->completed) != ACCESS_ONCE(rsp->gpnum) &&
+ if (rcu_gp_in_progress(rsp) &&
((long)(ACCESS_ONCE(rsp->jiffies_force_qs) - jiffies) < 0)) {
rdp->n_rp_need_fqs++;
return 1;
@@ -1368,6 +1397,82 @@ int rcu_needs_cpu(int cpu)
rcu_preempt_needs_cpu(cpu);
}
+static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL};
+static atomic_t rcu_barrier_cpu_count;
+static DEFINE_MUTEX(rcu_barrier_mutex);
+static struct completion rcu_barrier_completion;
+
+static void rcu_barrier_callback(struct rcu_head *notused)
+{
+ if (atomic_dec_and_test(&rcu_barrier_cpu_count))
+ complete(&rcu_barrier_completion);
+}
+
+/*
+ * Called with preemption disabled, and from cross-cpu IRQ context.
+ */
+static void rcu_barrier_func(void *type)
+{
+ int cpu = smp_processor_id();
+ struct rcu_head *head = &per_cpu(rcu_barrier_head, cpu);
+ void (*call_rcu_func)(struct rcu_head *head,
+ void (*func)(struct rcu_head *head));
+
+ atomic_inc(&rcu_barrier_cpu_count);
+ call_rcu_func = type;
+ call_rcu_func(head, rcu_barrier_callback);
+}
+
+/*
+ * Orchestrate the specified type of RCU barrier, waiting for all
+ * RCU callbacks of the specified type to complete.
+ */
+static void _rcu_barrier(struct rcu_state *rsp,
+ void (*call_rcu_func)(struct rcu_head *head,
+ void (*func)(struct rcu_head *head)))
+{
+ BUG_ON(in_interrupt());
+ /* Take mutex to serialize concurrent rcu_barrier() requests. */
+ mutex_lock(&rcu_barrier_mutex);
+ init_completion(&rcu_barrier_completion);
+ /*
+ * Initialize rcu_barrier_cpu_count to 1, then invoke
+ * rcu_barrier_func() on each CPU, so that each CPU also has
+ * incremented rcu_barrier_cpu_count. Only then is it safe to
+ * decrement rcu_barrier_cpu_count -- otherwise the first CPU
+ * might complete its grace period before all of the other CPUs
+ * did their increment, causing this function to return too
+ * early.
+ */
+ atomic_set(&rcu_barrier_cpu_count, 1);
+ preempt_disable(); /* stop CPU_DYING from filling orphan_cbs_list */
+ rcu_adopt_orphan_cbs(rsp);
+ on_each_cpu(rcu_barrier_func, (void *)call_rcu_func, 1);
+ preempt_enable(); /* CPU_DYING can again fill orphan_cbs_list */
+ if (atomic_dec_and_test(&rcu_barrier_cpu_count))
+ complete(&rcu_barrier_completion);
+ wait_for_completion(&rcu_barrier_completion);
+ mutex_unlock(&rcu_barrier_mutex);
+}
+
+/**
+ * rcu_barrier_bh - Wait until all in-flight call_rcu_bh() callbacks complete.
+ */
+void rcu_barrier_bh(void)
+{
+ _rcu_barrier(&rcu_bh_state, call_rcu_bh);
+}
+EXPORT_SYMBOL_GPL(rcu_barrier_bh);
+
+/**
+ * rcu_barrier_sched - Wait for in-flight call_rcu_sched() callbacks.
+ */
+void rcu_barrier_sched(void)
+{
+ _rcu_barrier(&rcu_sched_state, call_rcu_sched);
+}
+EXPORT_SYMBOL_GPL(rcu_barrier_sched);
+
/*
* Do boot-time initialization of a CPU's per-CPU RCU data.
*/
@@ -1464,6 +1569,22 @@ int __cpuinit rcu_cpu_notify(struct notifier_block *self,
case CPU_UP_PREPARE_FROZEN:
rcu_online_cpu(cpu);
break;
+ case CPU_DYING:
+ case CPU_DYING_FROZEN:
+ /*
+ * preempt_disable() in _rcu_barrier() prevents stop_machine(),
+ * so when "on_each_cpu(rcu_barrier_func, (void *)type, 1);"
+ * returns, all online cpus have queued rcu_barrier_func().
+ * The dying CPU clears its cpu_online_mask bit and
+ * moves all of its RCU callbacks to ->orphan_cbs_list
+ * in the context of stop_machine(), so subsequent calls
+ * to _rcu_barrier() will adopt these callbacks and only
+ * then queue rcu_barrier_func() on all remaining CPUs.
+ */
+ rcu_send_cbs_to_orphanage(&rcu_bh_state);
+ rcu_send_cbs_to_orphanage(&rcu_sched_state);
+ rcu_preempt_send_cbs_to_orphanage();
+ break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
case CPU_UP_CANCELED:
@@ -1526,7 +1647,8 @@ 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++) {
- spin_lock_init(&rnp->lock);
+ if (rnp != rcu_get_root(rsp))
+ spin_lock_init(&rnp->lock);
rnp->gpnum = 0;
rnp->qsmask = 0;
rnp->qsmaskinit = 0;
@@ -1549,6 +1671,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);
}
/*
@@ -1558,6 +1681,10 @@ static void __init rcu_init_one(struct rcu_state *rsp)
*/
#define RCU_INIT_FLAVOR(rsp, rcu_data) \
do { \
+ int i; \
+ int j; \
+ struct rcu_node *rnp; \
+ \
rcu_init_one(rsp); \
rnp = (rsp)->level[NUM_RCU_LVLS - 1]; \
j = 0; \
@@ -1570,31 +1697,8 @@ do { \
} \
} while (0)
-#ifdef CONFIG_TREE_PREEMPT_RCU
-
-void __init __rcu_init_preempt(void)
-{
- int i; /* All used by RCU_INIT_FLAVOR(). */
- int j;
- struct rcu_node *rnp;
-
- RCU_INIT_FLAVOR(&rcu_preempt_state, rcu_preempt_data);
-}
-
-#else /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-
-void __init __rcu_init_preempt(void)
-{
-}
-
-#endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */
-
void __init __rcu_init(void)
{
- int i; /* All used by RCU_INIT_FLAVOR(). */
- int j;
- struct rcu_node *rnp;
-
rcu_bootup_announce();
#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
printk(KERN_INFO "RCU-based detection of stalled CPUs is enabled.\n");
@@ -1605,6 +1709,4 @@ void __init __rcu_init(void)
open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
}
-module_param(blimit, int, 0);
-module_param(qhimark, int, 0);
-module_param(qlowmark, int, 0);
+#include "rcutree_plugin.h"
diff --git a/kernel/rcutree.h b/kernel/rcutree.h
index 8e8287a983c2..b40ac5706040 100644
--- a/kernel/rcutree.h
+++ b/kernel/rcutree.h
@@ -48,14 +48,14 @@
#elif NR_CPUS <= RCU_FANOUT_SQ
# define NUM_RCU_LVLS 2
# define NUM_RCU_LVL_0 1
-# define NUM_RCU_LVL_1 (((NR_CPUS) + RCU_FANOUT - 1) / RCU_FANOUT)
+# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT)
# define NUM_RCU_LVL_2 (NR_CPUS)
# define NUM_RCU_LVL_3 0
#elif NR_CPUS <= RCU_FANOUT_CUBE
# define NUM_RCU_LVLS 3
# define NUM_RCU_LVL_0 1
-# define NUM_RCU_LVL_1 (((NR_CPUS) + RCU_FANOUT_SQ - 1) / RCU_FANOUT_SQ)
-# define NUM_RCU_LVL_2 (((NR_CPUS) + (RCU_FANOUT) - 1) / (RCU_FANOUT))
+# define NUM_RCU_LVL_1 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_SQ)
+# define NUM_RCU_LVL_2 DIV_ROUND_UP(NR_CPUS, RCU_FANOUT)
# define NUM_RCU_LVL_3 NR_CPUS
#else
# error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"
@@ -79,15 +79,21 @@ struct rcu_dynticks {
* Definition for node within the RCU grace-period-detection hierarchy.
*/
struct rcu_node {
- spinlock_t lock;
+ spinlock_t lock; /* Root rcu_node's lock protects some */
+ /* rcu_state fields as well as following. */
long gpnum; /* Current grace period for this node. */
/* This will either be equal to or one */
/* behind the root rcu_node's gpnum. */
unsigned long qsmask; /* CPUs or groups that need to switch in */
/* order for current grace period to proceed.*/
+ /* In leaf rcu_node, each bit corresponds to */
+ /* an rcu_data structure, otherwise, each */
+ /* bit corresponds to a child rcu_node */
+ /* structure. */
unsigned long qsmaskinit;
/* Per-GP initialization for qsmask. */
unsigned long grpmask; /* Mask to apply to parent qsmask. */
+ /* Only one bit will be set in this mask. */
int grplo; /* lowest-numbered CPU or group here. */
int grphi; /* highest-numbered CPU or group here. */
u8 grpnum; /* CPU/group number for next level up. */
@@ -95,8 +101,23 @@ struct rcu_node {
struct rcu_node *parent;
struct list_head blocked_tasks[2];
/* Tasks blocked in RCU read-side critsect. */
+ /* Grace period number (->gpnum) x blocked */
+ /* by tasks on the (x & 0x1) element of the */
+ /* blocked_tasks[] array. */
} ____cacheline_internodealigned_in_smp;
+/*
+ * Do a full breadth-first scan of the rcu_node structures for the
+ * specified rcu_state structure.
+ */
+#define rcu_for_each_node_breadth_first(rsp, rnp) \
+ for ((rnp) = &(rsp)->node[0]; \
+ (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++)
+
+#define rcu_for_each_leaf_node(rsp, rnp) \
+ for ((rnp) = (rsp)->level[NUM_RCU_LVLS - 1]; \
+ (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++)
+
/* Index values for nxttail array in struct rcu_data. */
#define RCU_DONE_TAIL 0 /* Also RCU_WAIT head. */
#define RCU_WAIT_TAIL 1 /* Also RCU_NEXT_READY head. */
@@ -126,19 +147,22 @@ struct rcu_data {
* Any of the partitions might be empty, in which case the
* pointer to that partition will be equal to the pointer for
* the following partition. When the list is empty, all of
- * the nxttail elements point to nxtlist, which is NULL.
+ * the nxttail elements point to the ->nxtlist pointer itself,
+ * which in that case is NULL.
*
- * [*nxttail[RCU_NEXT_READY_TAIL], NULL = *nxttail[RCU_NEXT_TAIL]):
- * Entries that might have arrived after current GP ended
- * [*nxttail[RCU_WAIT_TAIL], *nxttail[RCU_NEXT_READY_TAIL]):
- * Entries known to have arrived before current GP ended
- * [*nxttail[RCU_DONE_TAIL], *nxttail[RCU_WAIT_TAIL]):
- * Entries that batch # <= ->completed - 1: waiting for current GP
* [nxtlist, *nxttail[RCU_DONE_TAIL]):
* Entries that batch # <= ->completed
* The grace period for these entries has completed, and
* the other grace-period-completed entries may be moved
* here temporarily in rcu_process_callbacks().
+ * [*nxttail[RCU_DONE_TAIL], *nxttail[RCU_WAIT_TAIL]):
+ * Entries that batch # <= ->completed - 1: waiting for current GP
+ * [*nxttail[RCU_WAIT_TAIL], *nxttail[RCU_NEXT_READY_TAIL]):
+ * Entries known to have arrived before current GP ended
+ * [*nxttail[RCU_NEXT_READY_TAIL], *nxttail[RCU_NEXT_TAIL]):
+ * Entries that might have arrived after current GP ended
+ * Note that the value of *nxttail[RCU_NEXT_TAIL] will
+ * always be NULL, as this is the end of the list.
*/
struct rcu_head *nxtlist;
struct rcu_head **nxttail[RCU_NEXT_SIZE];
@@ -216,8 +240,19 @@ struct rcu_state {
/* Force QS state. */
long gpnum; /* Current gp number. */
long completed; /* # of last completed gp. */
+
+ /* End of fields guarded by root rcu_node's lock. */
+
spinlock_t onofflock; /* exclude on/offline and */
- /* starting new GP. */
+ /* starting new GP. Also */
+ /* protects the following */
+ /* orphan_cbs fields. */
+ struct rcu_head *orphan_cbs_list; /* list of rcu_head structs */
+ /* orphaned by all CPUs in */
+ /* a given leaf rcu_node */
+ /* going offline. */
+ struct rcu_head **orphan_cbs_tail; /* And tail pointer. */
+ long orphan_qlen; /* Number of orphaned cbs. */
spinlock_t fqslock; /* Only one task forcing */
/* quiescent states. */
unsigned long jiffies_force_qs; /* Time at which to invoke */
@@ -255,5 +290,30 @@ extern struct rcu_state rcu_preempt_state;
DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data);
#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
-#endif /* #ifdef RCU_TREE_NONCORE */
+#else /* #ifdef RCU_TREE_NONCORE */
+
+/* Forward declarations for rcutree_plugin.h */
+static inline void rcu_bootup_announce(void);
+long rcu_batches_completed(void);
+static void rcu_preempt_note_context_switch(int cpu);
+static int rcu_preempted_readers(struct rcu_node *rnp);
+#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
+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 void rcu_preempt_offline_cpu(int cpu);
+#endif /* #ifdef CONFIG_HOTPLUG_CPU */
+static void rcu_preempt_check_callbacks(int cpu);
+static void rcu_preempt_process_callbacks(void);
+void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
+static int rcu_preempt_pending(int cpu);
+static int rcu_preempt_needs_cpu(int cpu);
+static void __cpuinit rcu_preempt_init_percpu_data(int cpu);
+static void rcu_preempt_send_cbs_to_orphanage(void);
+static void __init __rcu_init_preempt(void);
+#endif /* #else #ifdef RCU_TREE_NONCORE */
diff --git a/kernel/rcutree_plugin.h b/kernel/rcutree_plugin.h
index 1cee04f627eb..c0cb783aa16a 100644
--- a/kernel/rcutree_plugin.h
+++ b/kernel/rcutree_plugin.h
@@ -150,6 +150,16 @@ void __rcu_read_lock(void)
}
EXPORT_SYMBOL_GPL(__rcu_read_lock);
+/*
+ * Check for preempted RCU readers blocking the current grace period
+ * for the specified rcu_node structure. If the caller needs a reliable
+ * answer, it must hold the rcu_node's ->lock.
+ */
+static int rcu_preempted_readers(struct rcu_node *rnp)
+{
+ return !list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1]);
+}
+
static void rcu_read_unlock_special(struct task_struct *t)
{
int empty;
@@ -196,7 +206,7 @@ static void rcu_read_unlock_special(struct task_struct *t)
break;
spin_unlock(&rnp->lock); /* irqs remain disabled. */
}
- empty = list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1]);
+ empty = !rcu_preempted_readers(rnp);
list_del_init(&t->rcu_node_entry);
t->rcu_blocked_node = NULL;
@@ -207,7 +217,7 @@ static void rcu_read_unlock_special(struct task_struct *t)
* drop rnp->lock and restore irq.
*/
if (!empty && rnp->qsmask == 0 &&
- list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1])) {
+ !rcu_preempted_readers(rnp)) {
struct rcu_node *rnp_p;
if (rnp->parent == NULL) {
@@ -257,12 +267,12 @@ static void rcu_print_task_stall(struct rcu_node *rnp)
{
unsigned long flags;
struct list_head *lp;
- int phase = rnp->gpnum & 0x1;
+ int phase;
struct task_struct *t;
- if (!list_empty(&rnp->blocked_tasks[phase])) {
+ if (rcu_preempted_readers(rnp)) {
spin_lock_irqsave(&rnp->lock, flags);
- phase = rnp->gpnum & 0x1; /* re-read under lock. */
+ phase = rnp->gpnum & 0x1;
lp = &rnp->blocked_tasks[phase];
list_for_each_entry(t, lp, rcu_node_entry)
printk(" P%d", t->pid);
@@ -281,20 +291,10 @@ static void rcu_print_task_stall(struct rcu_node *rnp)
*/
static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp)
{
- WARN_ON_ONCE(!list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1]));
+ WARN_ON_ONCE(rcu_preempted_readers(rnp));
WARN_ON_ONCE(rnp->qsmask);
}
-/*
- * Check for preempted RCU readers for the specified rcu_node structure.
- * If the caller needs a reliable answer, it must hold the rcu_node's
- * >lock.
- */
-static int rcu_preempted_readers(struct rcu_node *rnp)
-{
- return !list_empty(&rnp->blocked_tasks[rnp->gpnum & 0x1]);
-}
-
#ifdef CONFIG_HOTPLUG_CPU
/*
@@ -410,6 +410,15 @@ static int rcu_preempt_needs_cpu(int cpu)
return !!per_cpu(rcu_preempt_data, cpu).nxtlist;
}
+/**
+ * rcu_barrier - Wait until all in-flight call_rcu() callbacks complete.
+ */
+void rcu_barrier(void)
+{
+ _rcu_barrier(&rcu_preempt_state, call_rcu);
+}
+EXPORT_SYMBOL_GPL(rcu_barrier);
+
/*
* Initialize preemptable RCU's per-CPU data.
*/
@@ -419,6 +428,22 @@ static void __cpuinit rcu_preempt_init_percpu_data(int cpu)
}
/*
+ * Move preemptable RCU's callbacks to ->orphan_cbs_list.
+ */
+static void rcu_preempt_send_cbs_to_orphanage(void)
+{
+ rcu_send_cbs_to_orphanage(&rcu_preempt_state);
+}
+
+/*
+ * Initialize preemptable RCU's state structures.
+ */
+static void __init __rcu_init_preempt(void)
+{
+ RCU_INIT_FLAVOR(&rcu_preempt_state, rcu_preempt_data);
+}
+
+/*
* Check for a task exiting while in a preemptable-RCU read-side
* critical section, clean up if so. No need to issue warnings,
* as debug_check_no_locks_held() already does this if lockdep
@@ -461,6 +486,15 @@ static void rcu_preempt_note_context_switch(int cpu)
{
}
+/*
+ * Because preemptable RCU does not exist, there are never any preempted
+ * RCU readers.
+ */
+static int rcu_preempted_readers(struct rcu_node *rnp)
+{
+ return 0;
+}
+
#ifdef CONFIG_RCU_CPU_STALL_DETECTOR
/*
@@ -483,15 +517,6 @@ static void rcu_preempt_check_blocked_tasks(struct rcu_node *rnp)
WARN_ON_ONCE(rnp->qsmask);
}
-/*
- * Because preemptable RCU does not exist, there are never any preempted
- * RCU readers.
- */
-static int rcu_preempted_readers(struct rcu_node *rnp)
-{
- return 0;
-}
-
#ifdef CONFIG_HOTPLUG_CPU
/*
@@ -518,7 +543,7 @@ static void rcu_preempt_offline_cpu(int cpu)
* Because preemptable RCU does not exist, it never has any callbacks
* to check.
*/
-void rcu_preempt_check_callbacks(int cpu)
+static void rcu_preempt_check_callbacks(int cpu)
{
}
@@ -526,7 +551,7 @@ void rcu_preempt_check_callbacks(int cpu)
* Because preemptable RCU does not exist, it never has any callbacks
* to process.
*/
-void rcu_preempt_process_callbacks(void)
+static void rcu_preempt_process_callbacks(void)
{
}
@@ -556,6 +581,16 @@ static int rcu_preempt_needs_cpu(int cpu)
}
/*
+ * Because preemptable RCU does not exist, rcu_barrier() is just
+ * another name for rcu_barrier_sched().
+ */
+void rcu_barrier(void)
+{
+ rcu_barrier_sched();
+}
+EXPORT_SYMBOL_GPL(rcu_barrier);
+
+/*
* Because preemptable RCU does not exist, there is no per-CPU
* data to initialize.
*/
@@ -563,4 +598,18 @@ static void __cpuinit rcu_preempt_init_percpu_data(int cpu)
{
}
+/*
+ * Because there is no preemptable RCU, there are no callbacks to move.
+ */
+static void rcu_preempt_send_cbs_to_orphanage(void)
+{
+}
+
+/*
+ * Because preemptable RCU does not exist, it need not be initialized.
+ */
+static void __init __rcu_init_preempt(void)
+{
+}
+
#endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c
index 179e6ad80dc0..4b31c779e62e 100644
--- a/kernel/rcutree_trace.c
+++ b/kernel/rcutree_trace.c
@@ -159,13 +159,13 @@ static void print_one_rcu_state(struct seq_file *m, struct rcu_state *rsp)
struct rcu_node *rnp;
seq_printf(m, "c=%ld g=%ld s=%d jfq=%ld j=%x "
- "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu\n",
+ "nfqs=%lu/nfqsng=%lu(%lu) fqlh=%lu oqlen=%ld\n",
rsp->completed, rsp->gpnum, rsp->signaled,
(long)(rsp->jiffies_force_qs - jiffies),
(int)(jiffies & 0xffff),
rsp->n_force_qs, rsp->n_force_qs_ngp,
rsp->n_force_qs - rsp->n_force_qs_ngp,
- rsp->n_force_qs_lh);
+ rsp->n_force_qs_lh, rsp->orphan_qlen);
for (rnp = &rsp->node[0]; rnp - &rsp->node[0] < NUM_RCU_NODES; rnp++) {
if (rnp->level != level) {
seq_puts(m, "\n");
diff --git a/kernel/sched.c b/kernel/sched.c
index 1535f3884b88..e88689522e66 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -676,6 +676,7 @@ inline void update_rq_clock(struct rq *rq)
/**
* runqueue_is_locked
+ * @cpu: the processor in question.
*
* Returns true if the current cpu runqueue is locked.
* This interface allows printk to be called with the runqueue lock
@@ -2311,7 +2312,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state,
{
int cpu, orig_cpu, this_cpu, success = 0;
unsigned long flags;
- struct rq *rq;
+ struct rq *rq, *orig_rq;
if (!sched_feat(SYNC_WAKEUPS))
wake_flags &= ~WF_SYNC;
@@ -2319,7 +2320,7 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state,
this_cpu = get_cpu();
smp_wmb();
- rq = task_rq_lock(p, &flags);
+ rq = orig_rq = task_rq_lock(p, &flags);
update_rq_clock(rq);
if (!(p->state & state))
goto out;
@@ -2350,6 +2351,10 @@ static int try_to_wake_up(struct task_struct *p, unsigned int state,
set_task_cpu(p, cpu);
rq = task_rq_lock(p, &flags);
+
+ if (rq != orig_rq)
+ update_rq_clock(rq);
+
WARN_ON(p->state != TASK_WAKING);
cpu = task_cpu(p);
@@ -2515,22 +2520,17 @@ void sched_fork(struct task_struct *p, int clone_flags)
__sched_fork(p);
/*
- * Make sure we do not leak PI boosting priority to the child.
- */
- p->prio = current->normal_prio;
-
- /*
* Revert to default priority/policy on fork if requested.
*/
if (unlikely(p->sched_reset_on_fork)) {
- if (p->policy == SCHED_FIFO || p->policy == SCHED_RR)
+ if (p->policy == SCHED_FIFO || p->policy == SCHED_RR) {
p->policy = SCHED_NORMAL;
-
- if (p->normal_prio < DEFAULT_PRIO)
- p->prio = DEFAULT_PRIO;
+ p->normal_prio = p->static_prio;
+ }
if (PRIO_TO_NICE(p->static_prio) < 0) {
p->static_prio = NICE_TO_PRIO(0);
+ p->normal_prio = p->static_prio;
set_load_weight(p);
}
@@ -2541,6 +2541,11 @@ void sched_fork(struct task_struct *p, int clone_flags)
p->sched_reset_on_fork = 0;
}
+ /*
+ * Make sure we do not leak PI boosting priority to the child.
+ */
+ p->prio = current->normal_prio;
+
if (!rt_prio(p->prio))
p->sched_class = &fair_sched_class;
@@ -2581,8 +2586,6 @@ void wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
BUG_ON(p->state != TASK_RUNNING);
update_rq_clock(rq);
- p->prio = effective_prio(p);
-
if (!p->sched_class->task_new || !current->se.on_rq) {
activate_task(rq, p, 0);
} else {
@@ -3658,6 +3661,7 @@ static void update_group_power(struct sched_domain *sd, int cpu)
/**
* update_sg_lb_stats - Update sched_group's statistics for load balancing.
+ * @sd: The sched_domain whose statistics are to be updated.
* @group: sched_group whose statistics are to be updated.
* @this_cpu: Cpu for which load balance is currently performed.
* @idle: Idle status of this_cpu
@@ -6720,9 +6724,6 @@ EXPORT_SYMBOL(yield);
/*
* This task is about to go to sleep on IO. Increment rq->nr_iowait so
* that process accounting knows that this is a task in IO wait state.
- *
- * But don't do that if it is a deliberate, throttling IO wait (this task
- * has set its backing_dev_info: the queue against which it should throttle)
*/
void __sched io_schedule(void)
{
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/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/time/tick-sched.c b/kernel/time/tick-sched.c
index e0f59a21c061..89aed5933ed4 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -231,6 +231,13 @@ void tick_nohz_stop_sched_tick(int inidle)
if (!inidle && !ts->inidle)
goto end;
+ /*
+ * Set ts->inidle unconditionally. Even if the system did not
+ * switch to NOHZ mode the cpu frequency governers rely on the
+ * update of the idle time accounting in tick_nohz_start_idle().
+ */
+ ts->inidle = 1;
+
now = tick_nohz_start_idle(ts);
/*
@@ -248,8 +255,6 @@ void tick_nohz_stop_sched_tick(int inidle)
if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE))
goto end;
- ts->inidle = 1;
-
if (need_resched())
goto end;
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index fb0f46fa1ecd..c3a4e2907eaa 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -13,6 +13,7 @@
#include <linux/percpu.h>
#include <linux/init.h>
#include <linux/mm.h>
+#include <linux/sched.h>
#include <linux/sysdev.h>
#include <linux/clocksource.h>
#include <linux/jiffies.h>
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 46592feab5a6..37ba67e33265 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -225,7 +225,11 @@ static void ftrace_update_pid_func(void)
if (ftrace_trace_function == ftrace_stub)
return;
+#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST
func = ftrace_trace_function;
+#else
+ func = __ftrace_trace_function;
+#endif
if (ftrace_pid_trace) {
set_ftrace_pid_function(func);
@@ -1074,14 +1078,9 @@ static void ftrace_replace_code(int enable)
failed = __ftrace_replace_code(rec, enable);
if (failed) {
rec->flags |= FTRACE_FL_FAILED;
- if ((system_state == SYSTEM_BOOTING) ||
- !core_kernel_text(rec->ip)) {
- ftrace_free_rec(rec);
- } else {
- ftrace_bug(failed, rec->ip);
- /* Stop processing */
- return;
- }
+ ftrace_bug(failed, rec->ip);
+ /* Stop processing */
+ return;
}
} while_for_each_ftrace_rec();
}
@@ -2658,19 +2657,17 @@ static int ftrace_convert_nops(struct module *mod,
}
#ifdef CONFIG_MODULES
-void ftrace_release(void *start, void *end)
+void ftrace_release_mod(struct module *mod)
{
struct dyn_ftrace *rec;
struct ftrace_page *pg;
- unsigned long s = (unsigned long)start;
- unsigned long e = (unsigned long)end;
- if (ftrace_disabled || !start || start == end)
+ if (ftrace_disabled)
return;
mutex_lock(&ftrace_lock);
do_for_each_ftrace_rec(pg, rec) {
- if ((rec->ip >= s) && (rec->ip < e)) {
+ if (within_module_core(rec->ip, mod)) {
/*
* rec->ip is changed in ftrace_free_rec()
* It should not between s and e if record was freed.
@@ -2702,9 +2699,7 @@ static int ftrace_module_notify(struct notifier_block *self,
mod->num_ftrace_callsites);
break;
case MODULE_STATE_GOING:
- ftrace_release(mod->ftrace_callsites,
- mod->ftrace_callsites +
- mod->num_ftrace_callsites);
+ ftrace_release_mod(mod);
break;
}
diff --git a/kernel/trace/kmemtrace.c b/kernel/trace/kmemtrace.c
index 81b1645c8549..a91da69f153a 100644
--- a/kernel/trace/kmemtrace.c
+++ b/kernel/trace/kmemtrace.c
@@ -501,7 +501,7 @@ static int __init init_kmem_tracer(void)
return 1;
}
- if (!register_tracer(&kmem_tracer)) {
+ if (register_tracer(&kmem_tracer) != 0) {
pr_warning("Warning: could not register the kmem tracer\n");
return 1;
}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 45068269ebb1..565eccfa4ce2 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>
@@ -1393,7 +1393,7 @@ int trace_array_vprintk(struct trace_array *tr,
int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
{
- return trace_array_printk(&global_trace, ip, fmt, args);
+ return trace_array_vprintk(&global_trace, ip, fmt, args);
}
EXPORT_SYMBOL_GPL(trace_vprintk);
diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c
index 7a7a9fd249a9..4a194f08f88c 100644
--- a/kernel/trace/trace_branch.c
+++ b/kernel/trace/trace_branch.c
@@ -34,6 +34,7 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
struct trace_array *tr = branch_tracer;
struct ring_buffer_event *event;
struct trace_branch *entry;
+ struct ring_buffer *buffer;
unsigned long flags;
int cpu, pc;
const char *p;
@@ -54,7 +55,8 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
goto out;
pc = preempt_count();
- event = trace_buffer_lock_reserve(tr, TRACE_BRANCH,
+ buffer = tr->buffer;
+ event = trace_buffer_lock_reserve(buffer, TRACE_BRANCH,
sizeof(*entry), flags, pc);
if (!event)
goto out;
@@ -74,8 +76,8 @@ probe_likely_condition(struct ftrace_branch_data *f, int val, int expect)
entry->line = f->line;
entry->correct = val == expect;
- if (!filter_check_discard(call, entry, tr->buffer, event))
- ring_buffer_unlock_commit(tr->buffer, event);
+ if (!filter_check_discard(call, entry, buffer, event))
+ ring_buffer_unlock_commit(buffer, event);
out:
atomic_dec(&tr->data[cpu]->disabled);
diff --git a/kernel/trace/trace_event_profile.c b/kernel/trace/trace_event_profile.c
index dd44b8768867..8d5c171cc998 100644
--- a/kernel/trace/trace_event_profile.c
+++ b/kernel/trace/trace_event_profile.c
@@ -31,7 +31,7 @@ static int ftrace_profile_enable_event(struct ftrace_event_call *event)
if (atomic_inc_return(&event->profile_count))
return 0;
- if (!total_profile_count++) {
+ if (!total_profile_count) {
buf = (char *)alloc_percpu(profile_buf_t);
if (!buf)
goto fail_buf;
@@ -46,14 +46,19 @@ static int ftrace_profile_enable_event(struct ftrace_event_call *event)
}
ret = event->profile_enable();
- if (!ret)
+ if (!ret) {
+ total_profile_count++;
return 0;
+ }
- kfree(trace_profile_buf_nmi);
fail_buf_nmi:
- kfree(trace_profile_buf);
+ if (!total_profile_count) {
+ free_percpu(trace_profile_buf_nmi);
+ free_percpu(trace_profile_buf);
+ trace_profile_buf_nmi = NULL;
+ trace_profile_buf = NULL;
+ }
fail_buf:
- total_profile_count--;
atomic_dec(&event->profile_count);
return ret;
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 23245785927f..98a6cc5c64ed 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -933,8 +933,9 @@ static void postfix_clear(struct filter_parse_state *ps)
while (!list_empty(&ps->postfix)) {
elt = list_first_entry(&ps->postfix, struct postfix_elt, list);
- kfree(elt->operand);
list_del(&elt->list);
+ kfree(elt->operand);
+ kfree(elt);
}
}
diff --git a/kernel/trace/trace_hw_branches.c b/kernel/trace/trace_hw_branches.c
index 23b63859130e..69543a905cd5 100644
--- a/kernel/trace/trace_hw_branches.c
+++ b/kernel/trace/trace_hw_branches.c
@@ -165,6 +165,7 @@ void trace_hw_branch(u64 from, u64 to)
struct ftrace_event_call *call = &event_hw_branch;
struct trace_array *tr = hw_branch_trace;
struct ring_buffer_event *event;
+ struct ring_buffer *buf;
struct hw_branch_entry *entry;
unsigned long irq1;
int cpu;
@@ -180,7 +181,8 @@ void trace_hw_branch(u64 from, u64 to)
if (atomic_inc_return(&tr->data[cpu]->disabled) != 1)
goto out;
- event = trace_buffer_lock_reserve(tr, TRACE_HW_BRANCHES,
+ buf = tr->buffer;
+ event = trace_buffer_lock_reserve(buf, TRACE_HW_BRANCHES,
sizeof(*entry), 0, 0);
if (!event)
goto out;
@@ -189,8 +191,8 @@ void trace_hw_branch(u64 from, u64 to)
entry->ent.type = TRACE_HW_BRANCHES;
entry->from = from;
entry->to = to;
- if (!filter_check_discard(call, entry, tr->buffer, event))
- trace_buffer_unlock_commit(tr, event, 0, 0);
+ if (!filter_check_discard(call, entry, buf, event))
+ trace_buffer_unlock_commit(buf, event, 0, 0);
out:
atomic_dec(&tr->data[cpu]->disabled);
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index f572f44c6e1e..ed17565826b0 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -486,16 +486,18 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
hardirq ? 'h' : softirq ? 's' : '.'))
return 0;
- if (entry->lock_depth < 0)
- ret = trace_seq_putc(s, '.');
+ if (entry->preempt_count)
+ ret = trace_seq_printf(s, "%x", entry->preempt_count);
else
- ret = trace_seq_printf(s, "%d", entry->lock_depth);
+ ret = trace_seq_putc(s, '.');
+
if (!ret)
return 0;
- if (entry->preempt_count)
- return trace_seq_printf(s, "%x", entry->preempt_count);
- return trace_seq_putc(s, '.');
+ if (entry->lock_depth < 0)
+ return trace_seq_putc(s, '.');
+
+ return trace_seq_printf(s, "%d", entry->lock_depth);
}
static int
@@ -883,7 +885,7 @@ static int trace_ctxwake_raw(struct trace_iterator *iter, char S)
trace_assign_type(field, iter->ent);
if (!S)
- task_state_char(field->prev_state);
+ S = task_state_char(field->prev_state);
T = task_state_char(field->next_state);
if (!trace_seq_printf(&iter->seq, "%d %d %c %d %d %d %c\n",
field->prev_pid,
@@ -918,7 +920,7 @@ static int trace_ctxwake_hex(struct trace_iterator *iter, char S)
trace_assign_type(field, iter->ent);
if (!S)
- task_state_char(field->prev_state);
+ S = task_state_char(field->prev_state);
T = task_state_char(field->next_state);
SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid);
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 9fbce6c9d2e1..527e17eae575 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -166,7 +166,7 @@ int syscall_exit_format(struct ftrace_event_call *call, struct trace_seq *s)
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n"
"\tfield:%s %s;\toffset:%zu;\tsize:%zu;\n",
SYSCALL_FIELD(int, nr),
- SYSCALL_FIELD(unsigned long, ret));
+ SYSCALL_FIELD(long, ret));
if (!ret)
return 0;
@@ -212,7 +212,7 @@ int syscall_exit_define_fields(struct ftrace_event_call *call)
if (ret)
return ret;
- ret = trace_define_field(call, SYSCALL_FIELD(unsigned long, ret), 0,
+ ret = trace_define_field(call, SYSCALL_FIELD(long, ret), 0,
FILTER_OTHER);
return ret;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index addfe2df93b1..47cdd7e76f2b 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -640,6 +640,24 @@ int schedule_delayed_work(struct delayed_work *dwork,
EXPORT_SYMBOL(schedule_delayed_work);
/**
+ * flush_delayed_work - block until a dwork_struct's callback has terminated
+ * @dwork: the delayed work which is to be flushed
+ *
+ * Any timeout is cancelled, and any pending work is run immediately.
+ */
+void flush_delayed_work(struct delayed_work *dwork)
+{
+ if (del_timer_sync(&dwork->timer)) {
+ struct cpu_workqueue_struct *cwq;
+ cwq = wq_per_cpu(keventd_wq, get_cpu());
+ __queue_work(cwq, &dwork->work);
+ put_cpu();
+ }
+ flush_work(&dwork->work);
+}
+EXPORT_SYMBOL(flush_delayed_work);
+
+/**
* schedule_delayed_work_on - queue work in global workqueue on CPU after delay
* @cpu: cpu to use
* @dwork: job to be done
diff --git a/lib/Kconfig b/lib/Kconfig
index bb1326d3839c..1cfe51628e1b 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -200,4 +200,7 @@ config NLATTR
config GENERIC_ATOMIC64
bool
+config LRU_CACHE
+ tristate
+
endmenu
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 891155817bc6..11bdf7d19082 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -344,10 +344,31 @@ 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 && (X86 || ARM || PPC) && \
- !MEMORY_HOTPLUG
+ depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \
+ (X86 || ARM || PPC || S390)
+
select DEBUG_FS if SYSFS
select STACKTRACE if STACKTRACE_SUPPORT
select KALLSYMS
@@ -370,7 +391,7 @@ config DEBUG_KMEMLEAK
config DEBUG_KMEMLEAK_EARLY_LOG_SIZE
int "Maximum kmemleak early log entries"
depends on DEBUG_KMEMLEAK
- range 200 2000
+ range 200 40000
default 400
help
Kmemleak must track all the memory allocations to avoid
diff --git a/lib/Makefile b/lib/Makefile
index 2e78277eff9d..347ad8db29d3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -91,6 +91,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/debugobjects.c b/lib/debugobjects.c
index 2755a3bd16a1..eae56fddfa3b 100644
--- a/lib/debugobjects.c
+++ b/lib/debugobjects.c
@@ -9,6 +9,7 @@
*/
#include <linux/debugobjects.h>
#include <linux/interrupt.h>
+#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/hash.h>
diff --git a/lib/fault-inject.c b/lib/fault-inject.c
index f97af55bdd96..7e65af70635e 100644
--- a/lib/fault-inject.c
+++ b/lib/fault-inject.c
@@ -1,6 +1,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/random.h>
+#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/types.h>
#include <linux/fs.h>
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/mm/Kconfig b/mm/Kconfig
index edd300aca173..57963c6063d1 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -224,7 +224,9 @@ config KSM
the many instances by a single resident page with that content, so
saving memory until one or another app needs to modify the content.
Recommended for use with KVM, or with other duplicative applications.
- See Documentation/vm/ksm.txt for more information.
+ See Documentation/vm/ksm.txt for more information: KSM is inactive
+ until a program has madvised that an area is MADV_MERGEABLE, and
+ root has set /sys/kernel/mm/ksm/run to 1 (if CONFIG_SYSFS is set).
config DEFAULT_MMAP_MIN_ADDR
int "Low address space to protect from user allocation"
diff --git a/mm/Makefile b/mm/Makefile
index ebf849042ed3..e3980c2126ec 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -29,6 +29,7 @@ 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
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index 3d3accb1f800..5a37e2055717 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -92,7 +92,7 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)
"BdiDirtyThresh: %8lu kB\n"
"DirtyThresh: %8lu kB\n"
"BackgroundThresh: %8lu kB\n"
- "WriteBack threads:%8lu\n"
+ "WritebackThreads: %8lu\n"
"b_dirty: %8lu\n"
"b_io: %8lu\n"
"b_more_io: %8lu\n"
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 4ea4510e2996..8bf765c4f58d 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -833,12 +833,15 @@ static void early_alloc(struct early_log *log)
*/
rcu_read_lock();
object = create_object((unsigned long)log->ptr, log->size,
- log->min_count, GFP_KERNEL);
+ log->min_count, GFP_ATOMIC);
+ if (!object)
+ goto out;
spin_lock_irqsave(&object->lock, flags);
for (i = 0; i < log->trace_len; i++)
object->trace[i] = log->trace[i];
object->trace_len = log->trace_len;
spin_unlock_irqrestore(&object->lock, flags);
+out:
rcu_read_unlock();
}
diff --git a/mm/ksm.c b/mm/ksm.c
index f7edac356f46..bef1af4f77e3 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -184,11 +184,6 @@ static DEFINE_SPINLOCK(ksm_mmlist_lock);
sizeof(struct __struct), __alignof__(struct __struct),\
(__flags), NULL)
-static void __init ksm_init_max_kernel_pages(void)
-{
- ksm_max_kernel_pages = nr_free_buffer_pages() / 4;
-}
-
static int __init ksm_slab_init(void)
{
rmap_item_cache = KSM_KMEM_CACHE(rmap_item, 0);
@@ -1673,7 +1668,7 @@ static int __init ksm_init(void)
struct task_struct *ksm_thread;
int err;
- ksm_init_max_kernel_pages();
+ ksm_max_kernel_pages = totalram_pages / 4;
err = ksm_slab_init();
if (err)
@@ -1697,6 +1692,9 @@ static int __init ksm_init(void)
kthread_stop(ksm_thread);
goto out_free2;
}
+#else
+ ksm_run = KSM_RUN_MERGE; /* no way for user to start it */
+
#endif /* CONFIG_SYSFS */
return 0;
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index a3b14090b1fb..2c5d79236ead 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -566,7 +566,8 @@ static void balance_dirty_pages(struct address_space *mapping,
if (pages_written >= write_chunk)
break; /* We've done our duty */
- schedule_timeout_interruptible(pause);
+ __set_current_state(TASK_INTERRUPTIBLE);
+ io_schedule_timeout(pause);
/*
* Increase the delay for each loop, up to our previous
diff --git a/mm/percpu.c b/mm/percpu.c
index 4a048abad043..6af78c1ee704 100644
--- a/mm/percpu.c
+++ b/mm/percpu.c
@@ -1870,13 +1870,14 @@ int __init pcpu_embed_first_chunk(size_t reserved_size, ssize_t dyn_size,
max_distance = 0;
for (group = 0; group < ai->nr_groups; group++) {
ai->groups[group].base_offset = areas[group] - base;
- max_distance = max(max_distance, ai->groups[group].base_offset);
+ max_distance = max_t(size_t, max_distance,
+ ai->groups[group].base_offset);
}
max_distance += ai->unit_size;
/* warn if maximum distance is further than 75% of vmalloc space */
if (max_distance > (VMALLOC_END - VMALLOC_START) * 3 / 4) {
- pr_warning("PERCPU: max_distance=0x%lx too large for vmalloc "
+ pr_warning("PERCPU: max_distance=0x%zx too large for vmalloc "
"space 0x%lx\n",
max_distance, VMALLOC_END - VMALLOC_START);
#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK
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/vmalloc.c b/mm/vmalloc.c
index 69511e663234..0f551a4a44cd 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -12,6 +12,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/highmem.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
@@ -25,10 +26,10 @@
#include <linux/rcupdate.h>
#include <linux/pfn.h>
#include <linux/kmemleak.h>
-#include <linux/highmem.h>
#include <asm/atomic.h>
#include <asm/uaccess.h>
#include <asm/tlbflush.h>
+#include <asm/shmparam.h>
/*** Page table manipulation functions ***/
@@ -1156,12 +1157,11 @@ static void insert_vmalloc_vm(struct vm_struct *vm, struct vmap_area *va,
}
static struct vm_struct *__get_vm_area_node(unsigned long size,
- unsigned long flags, unsigned long start, unsigned long end,
- int node, gfp_t gfp_mask, void *caller)
+ unsigned long align, unsigned long flags, unsigned long start,
+ unsigned long end, int node, gfp_t gfp_mask, void *caller)
{
static struct vmap_area *va;
struct vm_struct *area;
- unsigned long align = 1;
BUG_ON(in_interrupt());
if (flags & VM_IOREMAP) {
@@ -1201,7 +1201,7 @@ static struct vm_struct *__get_vm_area_node(unsigned long size,
struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end)
{
- return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL,
+ return __get_vm_area_node(size, 1, flags, start, end, -1, GFP_KERNEL,
__builtin_return_address(0));
}
EXPORT_SYMBOL_GPL(__get_vm_area);
@@ -1210,7 +1210,7 @@ struct vm_struct *__get_vm_area_caller(unsigned long size, unsigned long flags,
unsigned long start, unsigned long end,
void *caller)
{
- return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL,
+ return __get_vm_area_node(size, 1, flags, start, end, -1, GFP_KERNEL,
caller);
}
@@ -1225,22 +1225,22 @@ struct vm_struct *__get_vm_area_caller(unsigned long size, unsigned long flags,
*/
struct vm_struct *get_vm_area(unsigned long size, unsigned long flags)
{
- return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END,
+ return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
-1, GFP_KERNEL, __builtin_return_address(0));
}
struct vm_struct *get_vm_area_caller(unsigned long size, unsigned long flags,
void *caller)
{
- return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END,
+ return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
-1, GFP_KERNEL, caller);
}
struct vm_struct *get_vm_area_node(unsigned long size, unsigned long flags,
int node, gfp_t gfp_mask)
{
- return __get_vm_area_node(size, flags, VMALLOC_START, VMALLOC_END, node,
- gfp_mask, __builtin_return_address(0));
+ return __get_vm_area_node(size, 1, flags, VMALLOC_START, VMALLOC_END,
+ node, gfp_mask, __builtin_return_address(0));
}
static struct vm_struct *find_vm_area(const void *addr)
@@ -1403,7 +1403,8 @@ void *vmap(struct page **pages, unsigned int count,
}
EXPORT_SYMBOL(vmap);
-static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
+static void *__vmalloc_node(unsigned long size, unsigned long align,
+ gfp_t gfp_mask, pgprot_t prot,
int node, void *caller);
static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
pgprot_t prot, int node, void *caller)
@@ -1417,7 +1418,7 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
area->nr_pages = nr_pages;
/* Please note that the recursion is strictly bounded. */
if (array_size > PAGE_SIZE) {
- pages = __vmalloc_node(array_size, gfp_mask | __GFP_ZERO,
+ pages = __vmalloc_node(array_size, 1, gfp_mask | __GFP_ZERO,
PAGE_KERNEL, node, caller);
area->flags |= VM_VPAGES;
} else {
@@ -1476,6 +1477,7 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
/**
* __vmalloc_node - allocate virtually contiguous memory
* @size: allocation size
+ * @align: desired alignment
* @gfp_mask: flags for the page level allocator
* @prot: protection mask for the allocated pages
* @node: node to use for allocation or -1
@@ -1485,8 +1487,9 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
* allocator with @gfp_mask flags. Map them into contiguous
* kernel virtual space, using a pagetable protection of @prot.
*/
-static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
- int node, void *caller)
+static void *__vmalloc_node(unsigned long size, unsigned long align,
+ gfp_t gfp_mask, pgprot_t prot,
+ int node, void *caller)
{
struct vm_struct *area;
void *addr;
@@ -1496,8 +1499,8 @@ static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
if (!size || (size >> PAGE_SHIFT) > totalram_pages)
return NULL;
- area = __get_vm_area_node(size, VM_ALLOC, VMALLOC_START, VMALLOC_END,
- node, gfp_mask, caller);
+ area = __get_vm_area_node(size, align, VM_ALLOC, VMALLOC_START,
+ VMALLOC_END, node, gfp_mask, caller);
if (!area)
return NULL;
@@ -1516,7 +1519,7 @@ static void *__vmalloc_node(unsigned long size, gfp_t gfp_mask, pgprot_t prot,
void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
{
- return __vmalloc_node(size, gfp_mask, prot, -1,
+ return __vmalloc_node(size, 1, gfp_mask, prot, -1,
__builtin_return_address(0));
}
EXPORT_SYMBOL(__vmalloc);
@@ -1532,7 +1535,7 @@ EXPORT_SYMBOL(__vmalloc);
*/
void *vmalloc(unsigned long size)
{
- return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL,
+ return __vmalloc_node(size, 1, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL,
-1, __builtin_return_address(0));
}
EXPORT_SYMBOL(vmalloc);
@@ -1549,7 +1552,8 @@ void *vmalloc_user(unsigned long size)
struct vm_struct *area;
void *ret;
- ret = __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
+ ret = __vmalloc_node(size, SHMLBA,
+ GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
PAGE_KERNEL, -1, __builtin_return_address(0));
if (ret) {
area = find_vm_area(ret);
@@ -1572,7 +1576,7 @@ EXPORT_SYMBOL(vmalloc_user);
*/
void *vmalloc_node(unsigned long size, int node)
{
- return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL,
+ return __vmalloc_node(size, 1, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL,
node, __builtin_return_address(0));
}
EXPORT_SYMBOL(vmalloc_node);
@@ -1595,7 +1599,7 @@ EXPORT_SYMBOL(vmalloc_node);
void *vmalloc_exec(unsigned long size)
{
- return __vmalloc_node(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC,
+ return __vmalloc_node(size, 1, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC,
-1, __builtin_return_address(0));
}
@@ -1616,7 +1620,7 @@ void *vmalloc_exec(unsigned long size)
*/
void *vmalloc_32(unsigned long size)
{
- return __vmalloc_node(size, GFP_VMALLOC32, PAGE_KERNEL,
+ return __vmalloc_node(size, 1, GFP_VMALLOC32, PAGE_KERNEL,
-1, __builtin_return_address(0));
}
EXPORT_SYMBOL(vmalloc_32);
@@ -1633,7 +1637,7 @@ void *vmalloc_32_user(unsigned long size)
struct vm_struct *area;
void *ret;
- ret = __vmalloc_node(size, GFP_VMALLOC32 | __GFP_ZERO, PAGE_KERNEL,
+ ret = __vmalloc_node(size, 1, GFP_VMALLOC32 | __GFP_ZERO, PAGE_KERNEL,
-1, __builtin_return_address(0));
if (ret) {
area = find_vm_area(ret);
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/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/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..4b66bd579f4a 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -3916,7 +3916,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/dev.c b/net/core/dev.c
index b8f74cfb1bfd..28b0b9e992a0 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -2604,20 +2604,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 +4829,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 +5482,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/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 821d30918cfc..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),
@@ -366,13 +406,13 @@ static ssize_t wireless_show(struct device *d, char *buf,
const struct iw_statistics *iw;
ssize_t ret = -EINVAL;
- read_lock(&dev_base_lock);
+ rtnl_lock();
if (dev_isalive(dev)) {
iw = get_wireless_stats(dev);
if (iw)
ret = (*format)(iw, buf);
}
- read_unlock(&dev_base_lock);
+ rtnl_unlock();
return ret;
}
@@ -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 b69455217ed6..1da0e038df78 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -964,7 +964,7 @@ static ssize_t pktgen_if_write(struct file *file,
if (value == 0x7FFFFFFF)
pkt_dev->delay = ULLONG_MAX;
else
- pkt_dev->delay = (u64)value * NSEC_PER_USEC;
+ pkt_dev->delay = (u64)value;
sprintf(pg_result, "OK: delay=%llu",
(unsigned long long) pkt_dev->delay);
@@ -2212,7 +2212,7 @@ static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
if (pkt_dev->flags & F_QUEUE_MAP_CPU)
pkt_dev->cur_queue_map = smp_processor_id();
- else if (pkt_dev->queue_map_min < pkt_dev->queue_map_max) {
+ else if (pkt_dev->queue_map_min <= pkt_dev->queue_map_max) {
__u16 t;
if (pkt_dev->flags & F_QUEUE_MAP_RND) {
t = random32() %
@@ -3441,12 +3441,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 +3470,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/sock.c b/net/core/sock.c
index 7626b6aacd68..38713aa3faf2 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);
@@ -702,6 +706,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 +911,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;
}
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/ipv6.c b/net/dccp/ipv6.c
index e48ca5d45658..a2afb553d8b3 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -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->daddr, &newnp->daddr);
- ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
- newinet->saddr);
+ ipv6_addr_set_v4mapped(newinet->saddr, &newnp->saddr);
ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
@@ -971,10 +969,8 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
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->saddr, &np->saddr);
+ ipv6_addr_set_v4mapped(inet->rcv_saddr, &np->rcv_saddr);
}
return err;
diff --git a/net/dccp/probe.c b/net/dccp/probe.c
index 37731da41481..5e6ec8b9b7b6 100644
--- a/net/dccp/probe.c
+++ b/net/dccp/probe.c
@@ -75,22 +75,20 @@ 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);
+ hc = 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",
+ if (hc)
+ 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->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),
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index a156319fd0ac..ecb203fff501 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -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/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 7a58c87baf17..4d3060660a14 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -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/af_inet.c b/net/ipv4/af_inet.c
index 57737b8d1711..1deff48b122e 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -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,
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/devinet.c b/net/ipv4/devinet.c
index e92f1fd28aa5..5df2f6a0b0f0 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1077,12 +1077,16 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
ip_mc_up(in_dev);
/* fall through */
case NETDEV_CHANGEADDR:
- if (IN_DEV_ARP_NOTIFY(in_dev))
- arp_send(ARPOP_REQUEST, ETH_P_ARP,
- in_dev->ifa_list->ifa_address,
- dev,
- in_dev->ifa_list->ifa_address,
- NULL, dev->dev_addr, NULL);
+ /* Send gratuitous ARP to notify of link change */
+ if (IN_DEV_ARP_NOTIFY(in_dev)) {
+ struct in_ifaddr *ifa = in_dev->ifa_list;
+
+ if (ifa)
+ arp_send(ARPOP_REQUEST, ETH_P_ARP,
+ ifa->ifa_address, dev,
+ ifa->ifa_address, NULL,
+ dev->dev_addr, NULL);
+ }
break;
case NETDEV_DOWN:
ip_mc_down(in_dev);
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..9139e8f6fdb1 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 :
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index a706a47f4dbb..cb73fdefba91 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -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;
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index 625cc5f64c94..a45aaf3d48b1 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -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();
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index 13f0781f35cd..2fe571155b22 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -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..89ff9d5b1500 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -662,7 +662,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 +811,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/ipip.c b/net/ipv4/ipip.c
index 08ccd344de7a..6a5539236ab3 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -390,7 +390,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 +479,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..c757f0b4b74c 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);
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 757c9171e7c2..39e2a6b8752c 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -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;
}
@@ -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) {
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..cf13726259cd 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2865,11 +2865,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 +2877,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 +2932,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..99718703d040 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2000,7 +2000,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 +2061,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));
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 624c3c9b3c2b..e320afea07fc 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -644,6 +644,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
/* If TCP_DEFER_ACCEPT is set, drop bare ACK. */
if (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/udp.c b/net/ipv4/udp.c
index 6ec6a8a4a224..45a8a7e374d8 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,9 +207,10 @@ 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:
@@ -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;
@@ -841,6 +845,42 @@ out:
return ret;
}
+
+/**
+ * first_packet_length - return length of first packet in receive queue
+ * @sk: socket
+ *
+ * Drops all bad checksum frames, until a valid one is found.
+ * Returns the length of found skb, or 0 if none is found.
+ */
+static unsigned int first_packet_length(struct sock *sk)
+{
+ struct sk_buff_head list_kill, *rcvq = &sk->sk_receive_queue;
+ struct sk_buff *skb;
+ unsigned int res;
+
+ __skb_queue_head_init(&list_kill);
+
+ spin_lock_bh(&rcvq->lock);
+ while ((skb = skb_peek(rcvq)) != NULL &&
+ udp_lib_checksum_complete(skb)) {
+ UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INERRORS,
+ IS_UDPLITE(sk));
+ __skb_unlink(skb, rcvq);
+ __skb_queue_tail(&list_kill, skb);
+ }
+ res = skb ? skb->len : 0;
+ spin_unlock_bh(&rcvq->lock);
+
+ if (!skb_queue_empty(&list_kill)) {
+ lock_sock(sk);
+ __skb_queue_purge(&list_kill);
+ sk_mem_reclaim_partial(sk);
+ release_sock(sk);
+ }
+ return res;
+}
+
/*
* IOCTL requests applicable to the UDP protocol
*/
@@ -857,21 +897,16 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
case SIOCINQ:
{
- struct sk_buff *skb;
- unsigned long amount;
+ unsigned int amount = first_packet_length(sk);
- amount = 0;
- spin_lock_bh(&sk->sk_receive_queue.lock);
- skb = skb_peek(&sk->sk_receive_queue);
- if (skb != NULL) {
+ if (amount)
/*
* We will only return the amount
* of this packet since that is all
* that will be read.
*/
- amount = skb->len - sizeof(struct udphdr);
- }
- spin_unlock_bh(&sk->sk_receive_queue.lock);
+ amount -= sizeof(struct udphdr);
+
return put_user(amount, (int __user *)arg);
}
@@ -951,7 +986,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) {
@@ -1013,8 +1048,8 @@ 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)) {
@@ -1028,25 +1063,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:
@@ -1169,7 +1201,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);
@@ -1540,29 +1572,11 @@ unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait)
{
unsigned int mask = datagram_poll(file, sock, wait);
struct sock *sk = sock->sk;
- int is_lite = IS_UDPLITE(sk);
/* Check for false positives due to checksum errors */
- if ((mask & POLLRDNORM) &&
- !(file->f_flags & O_NONBLOCK) &&
- !(sk->sk_shutdown & RCV_SHUTDOWN)) {
- struct sk_buff_head *rcvq = &sk->sk_receive_queue;
- struct sk_buff *skb;
-
- spin_lock_bh(&rcvq->lock);
- while ((skb = skb_peek(rcvq)) != NULL &&
- udp_lib_checksum_complete(skb)) {
- UDP_INC_STATS_BH(sock_net(sk),
- UDP_MIB_INERRORS, is_lite);
- __skb_unlink(skb, rcvq);
- kfree_skb(skb);
- }
- spin_unlock_bh(&rcvq->lock);
-
- /* nothing to see, move along */
- if (skb == NULL)
- mask &= ~(POLLIN | POLLRDNORM);
- }
+ if ((mask & POLLRDNORM) && !(file->f_flags & O_NONBLOCK) &&
+ !(sk->sk_shutdown & RCV_SHUTDOWN) && !first_packet_length(sk))
+ mask &= ~(POLLIN | POLLRDNORM);
return mask;
@@ -1609,9 +1623,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))
@@ -1636,7 +1655,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);
}
@@ -1656,7 +1675,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;
}
@@ -1678,7 +1697,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);
}
@@ -1738,7 +1757,7 @@ static void udp4_format_sock(struct sock *sp, struct seq_file *f,
__u16 destp = ntohs(inet->dport);
__u16 srcp = ntohs(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),
@@ -1804,11 +1823,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);
}
@@ -1818,7 +1869,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..94216519873c 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -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,6 +654,7 @@ 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.mark = sk->sk_mark;
fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport;
security_sk_classify_flow(sk, &fl);
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index e2bdc6d83a43..dbfec7147aa5 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -98,17 +98,14 @@ ipv4_connected:
if (err)
goto out;
- ipv6_addr_set(&np->daddr, 0, 0, htonl(0x0000ffff), inet->daddr);
+ ipv6_addr_set_v4mapped(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->saddr, &np->saddr);
+
+ if (ipv6_addr_any(&np->rcv_saddr))
+ ipv6_addr_set_v4mapped(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;
}
@@ -147,6 +144,7 @@ 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.mark = sk->sk_mark;
fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport;
@@ -329,9 +327,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 +348,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..a9f4a21b31ea 100644
--- a/net/ipv6/inet6_connection_sock.c
+++ b/net/ipv6/inet6_connection_sock.c
@@ -194,6 +194,7 @@ 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.mark = sk->sk_mark;
fl.fl_ip_sport = inet->sport;
fl.fl_ip_dport = inet->dport;
security_sk_classify_flow(sk, &fl);
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index 1bcc3431859e..874aed86e1a2 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];
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 14f54eb5a7fc..dc0f7366073d 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -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;
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..fd737efed96c 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -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;
}
@@ -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);
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..510d31f3cb96 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -161,6 +161,23 @@ static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t)
write_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,
struct ip_tunnel_parm *parms, int create)
{
@@ -204,6 +221,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;
@@ -532,17 +550,41 @@ out:
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 +597,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 +638,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 +731,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 +828,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 +847,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 +986,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 +1152,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;
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 6b6ae913b5d4..cbe55e5d9f96 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -252,6 +252,7 @@ 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;
security_req_classify_flow(req, &fl);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 21d100b68b19..451763059142 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -226,10 +226,8 @@ 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->saddr, &np->saddr);
+ ipv6_addr_set_v4mapped(inet->rcv_saddr, &np->rcv_saddr);
}
return err;
@@ -243,6 +241,7 @@ 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;
@@ -383,6 +382,7 @@ 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.mark = sk->sk_mark;
fl.fl_ip_dport = inet->dport;
fl.fl_ip_sport = inet->sport;
security_skb_classify_flow(skb, &fl);
@@ -477,6 +477,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 +1291,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->daddr, &newnp->daddr);
- ipv6_addr_set(&newnp->saddr, 0, 0, htonl(0x0000FFFF),
- newinet->saddr);
+ ipv6_addr_set_v4mapped(newinet->saddr, &newnp->saddr);
ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr);
@@ -1345,6 +1344,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);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 3a60f12b34ed..b86425b7ea22 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -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,13 +385,11 @@ 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;
}
@@ -452,7 +450,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);
@@ -879,6 +877,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));
@@ -1195,7 +1195,7 @@ static void udp6_sock_seq_show(struct seq_file *seq, struct sock *sp, int bucket
destp = ntohs(inet->dport);
srcp = ntohs(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/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/irda/ircomm/ircomm_tty_attach.c b/net/irda/ircomm/ircomm_tty_attach.c
index eafc010907c2..3c1754023022 100644
--- a/net/irda/ircomm/ircomm_tty_attach.c
+++ b/net/irda/ircomm/ircomm_tty_attach.c
@@ -30,6 +30,7 @@
********************************************************************/
#include <linux/init.h>
+#include <linux/sched.h>
#include <net/irda/irda.h>
#include <net/irda/irlmp.h>
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index 62116829b817..315ead3cb926 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -30,6 +30,7 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
+#include <linux/sched.h>
#include <linux/seq_file.h>
#include <linux/random.h>
#include <linux/netdevice.h>
diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c
index 7b6b631f647f..d340110f5c0c 100644
--- a/net/irda/irlan/irlan_eth.c
+++ b/net/irda/irlan/irlan_eth.c
@@ -30,6 +30,7 @@
#include <linux/inetdevice.h>
#include <linux/if_arp.h>
#include <linux/module.h>
+#include <linux/sched.h>
#include <net/arp.h>
#include <net/irda/irda.h>
diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c
index cf9a4b531a98..cccc2e93234f 100644
--- a/net/irda/irnet/irnet_irda.c
+++ b/net/irda/irnet/irnet_irda.c
@@ -9,6 +9,7 @@
*/
#include "irnet_irda.h" /* Private header */
+#include <linux/sched.h>
#include <linux/seq_file.h>
#include <asm/unaligned.h>
diff --git a/net/irda/irnet/irnet_ppp.c b/net/irda/irnet/irnet_ppp.c
index 68cbcb19cbd8..7dea882dbb75 100644
--- a/net/irda/irnet/irnet_ppp.c
+++ b/net/irda/irnet/irnet_ppp.c
@@ -13,6 +13,7 @@
* 2) as a control channel (write commands, read events)
*/
+#include <linux/sched.h>
#include <linux/smp_lock.h>
#include "irnet_ppp.h" /* Private header */
/* Please put other headers in irnet.h - Thanks */
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index bada1b9c670b..004134b60d86 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -1715,7 +1715,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 920ec8792f4b..6eaf69823439 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -544,7 +544,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
"%pM\n", bss->cbss.bssid, ifibss->bssid);
#endif /* CONFIG_MAC80211_IBSS_DEBUG */
- if (bss && memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN)) {
+ 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);
@@ -829,7 +829,7 @@ void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
if (!sdata->u.ibss.ssid_len)
continue;
sdata->u.ibss.last_scan_completed = jiffies;
- ieee80211_sta_find_ibss(sdata);
+ mod_timer(&sdata->u.ibss.timer, 0);
}
mutex_unlock(&local->iflist_mtx);
}
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/mlme.c b/net/mac80211/mlme.c
index 8d26e9bf8964..697a1499b07d 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();
@@ -1459,7 +1465,7 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
sdata->dev->name, status_code);
list_del(&wk->list);
kfree(wk);
- return RX_MGMT_CFG80211_ASSOC;
+ return RX_MGMT_CFG80211_DEAUTH;
}
if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
@@ -1959,12 +1965,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 +2023,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/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c
index a59043fbb0ff..45667054a5f3 100644
--- a/net/mac80211/rc80211_pid_debugfs.c
+++ b/net/mac80211/rc80211_pid_debugfs.c
@@ -6,6 +6,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/poll.h>
#include <linux/netdevice.h>
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index c01588f9d453..7170bf4565a8 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2164,11 +2164,17 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
skb = rx.skb;
- list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+ if (rx.sdata && ieee80211_is_data(hdr->frame_control)) {
+ rx.flags |= IEEE80211_RX_RA_MATCH;
+ prepares = prepare_for_handlers(rx.sdata, &rx, hdr);
+ if (prepares)
+ prev = rx.sdata;
+ } else list_for_each_entry_rcu(sdata, &local->interfaces, list) {
if (!netif_running(sdata->dev))
continue;
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
+ if (sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+ sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
continue;
rx.flags |= IEEE80211_RX_RA_MATCH;
@@ -2447,6 +2453,8 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
struct ieee80211_supported_band *sband;
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+ WARN_ON_ONCE(softirq_count() == 0);
+
if (WARN_ON(status->band < 0 ||
status->band >= IEEE80211_NUM_BANDS))
goto drop;
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/sta_info.c b/net/mac80211/sta_info.c
index eec001491e66..594f2318c3d8 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -361,6 +361,7 @@ int sta_info_insert(struct sta_info *sta)
u.ap);
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_ADD, &sta->sta);
+ sdata = sta->sdata;
}
#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
@@ -496,6 +497,7 @@ static void __sta_info_unlink(struct sta_info **sta)
drv_sta_notify(local, &sdata->vif, STA_NOTIFY_REMOVE,
&(*sta)->sta);
+ sdata = (*sta)->sdata;
}
if (ieee80211_vif_is_mesh(&sdata->vif)) {
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index fd4028296613..db4bda681ec9 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1704,7 +1704,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
if (!is_multicast_ether_addr(hdr.addr1)) {
rcu_read_lock();
sta = sta_info_get(local, hdr.addr1);
- if (sta)
+ /* XXX: in the future, use sdata to look up the sta */
+ if (sta && sta->sdata == sdata)
sta_flags = get_sta_flags(sta);
rcu_read_unlock();
}
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index dd6564321369..aeb65b3d2295 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -339,7 +339,7 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (WARN_ON(!info->control.vif)) {
- kfree(skb);
+ kfree_skb(skb);
return;
}
@@ -367,7 +367,7 @@ int ieee80211_add_pending_skbs(struct ieee80211_local *local,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (WARN_ON(!info->control.vif)) {
- kfree(skb);
+ kfree_skb(skb);
continue;
}
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 7c9ec3dee96e..ca6e68dcd8a8 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/netfilter.h>
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/vmalloc.h>
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/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..bf3a2954cd4d 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -490,6 +490,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 +627,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)) {
@@ -856,6 +856,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 +1126,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 +1477,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,
@@ -2363,7 +2365,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/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..ca2e1fd2bf69 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -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_pedit.c b/net/sched/act_pedit.c
index 96c0ed115e2a..6b0359a500e6 100644
--- a/net/sched/act_pedit.c
+++ b/net/sched/act_pedit.c
@@ -34,7 +34,7 @@ static struct tcf_hashinfo pedit_hash_info = {
};
static const struct nla_policy pedit_policy[TCA_PEDIT_MAX + 1] = {
- [TCA_PEDIT_PARMS] = { .len = sizeof(struct tcf_pedit) },
+ [TCA_PEDIT_PARMS] = { .len = sizeof(struct tc_pedit) },
};
static int tcf_pedit_init(struct nlattr *nla, struct nlattr *est,
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 6a536949cdc0..7cf6c0fbc7a6 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -350,7 +350,7 @@ static int tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp,
tcm = NLMSG_DATA(nlh);
tcm->tcm_family = AF_UNSPEC;
tcm->tcm__pad1 = 0;
- tcm->tcm__pad1 = 0;
+ tcm->tcm__pad2 = 0;
tcm->tcm_ifindex = qdisc_dev(tp->q)->ifindex;
tcm->tcm_parent = tp->classid;
tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol);
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/socket.c b/net/sctp/socket.c
index c8d05758661d..0970e92c6acd 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -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);
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..f4c7ff3a53e6 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -686,8 +686,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
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);
diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c
index 0cf5e8c27a10..3fa5751af0ec 100644
--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c
+++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c
@@ -42,6 +42,7 @@
#include <linux/sunrpc/svc_xprt.h>
#include <linux/sunrpc/debug.h>
#include <linux/sunrpc/rpc_rdma.h>
+#include <linux/sched.h>
#include <linux/spinlock.h>
#include <rdma/ib_verbs.h>
#include <rdma/rdma_cm.h>
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 51ab497115eb..0f133c5a8d3c 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2214,7 +2214,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 45b2be3274db..1758f2447ac8 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -14,6 +14,7 @@
#include <linux/device.h>
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
+#include <linux/sched.h>
#include <net/genetlink.h>
#include <net/cfg80211.h>
#include "nl80211.h"
@@ -21,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"
@@ -358,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;
@@ -625,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)
@@ -641,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
@@ -665,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;
@@ -681,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) {
@@ -689,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;
@@ -721,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);
@@ -759,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/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..1f87b4e7f4f7 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -121,7 +121,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 +130,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 +137,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 +146,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 +153,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 +171,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 +224,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 +310,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 eddab097435c..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:
@@ -4029,7 +4031,7 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
rdev = cfg80211_get_dev_from_info(info);
if (IS_ERR(rdev)) {
err = PTR_ERR(rdev);
- goto out;
+ goto out_rtnl;
}
net = get_net_ns_by_pid(pid);
@@ -4049,6 +4051,7 @@ static int nl80211_wiphy_netns(struct sk_buff *skb, struct genl_info *info)
put_net(net);
out:
cfg80211_unlock_rdev(rdev);
+ out_rtnl:
rtnl_unlock();
return err;
}
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..d3624152f7f7 100644
--- a/net/wireless/sme.c
+++ b/net/wireless/sme.c
@@ -345,7 +345,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 +362,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 +477,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 +512,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 +573,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 +631,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/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/Kbuild.include b/scripts/Kbuild.include
index 4f9c1908593b..c67e73ecd5be 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -100,7 +100,7 @@ as-option = $(call try-run,\
# Usage: cflags-y += $(call as-instr,instr,option1,option2)
as-instr = $(call try-run,\
- echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
+ /bin/echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3))
# cc-option
# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 7a7778746ea6..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 = 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/checkkconfigsymbols.sh b/scripts/checkkconfigsymbols.sh
index 39677c82747a..46be3c5a62b7 100755
--- a/scripts/checkkconfigsymbols.sh
+++ b/scripts/checkkconfigsymbols.sh
@@ -9,7 +9,7 @@ paths="$@"
# Doing this once at the beginning saves a lot of time, on a cache-hot tree.
Kconfigs="`find . -name 'Kconfig' -o -name 'Kconfig*[^~]'`"
-echo -e "File list \tundefined symbol used"
+/bin/echo -e "File list \tundefined symbol used"
find $paths -name '*.[chS]' -o -name 'Makefile' -o -name 'Makefile*[^~]'| while read i
do
# Output the bare Kconfig variable and the filename; the _MODULE part at
@@ -54,6 +54,6 @@ while read symb files; do
# beyond the purpose of this script.
symb_bare=`echo $symb | sed -e 's/_MODULE//'`
if ! grep -q "\<$symb_bare\>" $Kconfigs; then
- echo -e "$files: \t$symb"
+ /bin/echo -e "$files: \t$symb"
fi
done|sort
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_install.pl b/scripts/headers_install.pl
index c6ae4052ab43..b89ca2c58fdb 100644
--- a/scripts/headers_install.pl
+++ b/scripts/headers_install.pl
@@ -20,7 +20,7 @@ use strict;
my ($readdir, $installdir, $arch, @files) = @ARGV;
-my $unifdef = "scripts/unifdef -U__KERNEL__";
+my $unifdef = "scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__";
foreach my $file (@files) {
local *INFILE;
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 6a12dd9f1181..23dbad80cce9 100755
--- a/scripts/mkcompile_h
+++ b/scripts/mkcompile_h
@@ -1,3 +1,5 @@
+#!/bin/sh
+
TARGET=$1
ARCH=$2
SMP=$3
@@ -12,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
@@ -50,7 +52,7 @@ UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP"
# Truncate to maximum length
UTS_LEN=64
-UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/"
+UTS_TRUNCATE="cut -b -$UTS_LEN"
# Generate a temporary compile.h
@@ -66,9 +68,13 @@ UTS_TRUNCATE="sed -e s/\(.\{1,$UTS_LEN\}\).*/\1/"
echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
if [ -x /bin/dnsdomainname ]; then
- echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname | $UTS_TRUNCATE`\"
+ domain=`dnsdomainname 2> /dev/null`
elif [ -x /bin/domainname ]; then
- echo \#define LINUX_COMPILE_DOMAIN \"`domainname | $UTS_TRUNCATE`\"
+ domain=`domainname 2> /dev/null`
+ fi
+
+ if [ -n "$domain" ]; then
+ echo \#define LINUX_COMPILE_DOMAIN \"`echo $domain | $UTS_TRUNCATE`\"
else
echo \#define LINUX_COMPILE_DOMAIN
fi
diff --git a/scripts/package/Makefile b/scripts/package/Makefile
index fa4a0a17b7e0..f67cc885c807 100644
--- a/scripts/package/Makefile
+++ b/scripts/package/Makefile
@@ -18,6 +18,9 @@
# e) generate the rpm files, based on kernel.spec
# - Use /. to avoid tar packing just the symlink
+# Note that the rpm-pkg target cannot be used with KBUILD_OUTPUT,
+# but the binrpm-pkg target can; for some reason O= gets ignored.
+
# Do we have rpmbuild, otherwise fall back to the older rpm
RPM := $(shell if [ -x "/usr/bin/rpmbuild" ]; then echo rpmbuild; \
else echo rpm; fi)
@@ -33,6 +36,12 @@ $(objtree)/kernel.spec: $(MKSPEC) $(srctree)/Makefile
$(CONFIG_SHELL) $(MKSPEC) > $@
rpm-pkg rpm: $(objtree)/kernel.spec FORCE
+ @if test -n "$(KBUILD_OUTPUT)"; then \
+ echo "Building source + binary RPM is not possible outside the"; \
+ echo "kernel source tree. Don't set KBUILD_OUTPUT, or use the"; \
+ echo "binrpm-pkg target instead."; \
+ false; \
+ fi
$(MAKE) clean
$(PREV) ln -sf $(srctree) $(KERNELPATH)
$(CONFIG_SHELL) $(srctree)/scripts/setlocalversion > $(objtree)/.scmversion
@@ -61,7 +70,7 @@ binrpm-pkg: $(objtree)/binkernel.spec FORCE
set -e; \
mv -f $(objtree)/.tmp_version $(objtree)/.version
- $(RPM) $(RPMOPTS) --define "_builddir $(srctree)" --target \
+ $(RPM) $(RPMOPTS) --define "_builddir $(objtree)" --target \
$(UTS_MACHINE) -bb $<
clean-files += $(objtree)/binkernel.spec
diff --git a/scripts/package/mkspec b/scripts/package/mkspec
index 3d93f8c81252..47bdd2f99b78 100755
--- a/scripts/package/mkspec
+++ b/scripts/package/mkspec
@@ -70,7 +70,7 @@ echo 'mkdir -p $RPM_BUILD_ROOT/boot $RPM_BUILD_ROOT/lib/modules'
echo 'mkdir -p $RPM_BUILD_ROOT/lib/firmware'
echo "%endif"
-echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{_smp_mflags} modules_install'
+echo 'INSTALL_MOD_PATH=$RPM_BUILD_ROOT make %{_smp_mflags} KBUILD_SRC= modules_install'
echo "%ifarch ia64"
echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/efi/vmlinuz-$KERNELRELEASE"
echo 'ln -s '"efi/vmlinuz-$KERNELRELEASE" '$RPM_BUILD_ROOT'"/boot/"
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 2fb28efc5326..06ec722897be 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -873,7 +873,7 @@ static long get_instantiation_keyring(key_serial_t ringid,
/* otherwise specify the destination keyring recorded in the
* authorisation key (any KEY_SPEC_*_KEYRING) */
if (ringid >= KEY_SPEC_REQUESTOR_KEYRING) {
- *_dest_keyring = rka->dest_keyring;
+ *_dest_keyring = key_get(rka->dest_keyring);
return 0;
}
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index dc78272fc39f..1f0f8213e2d5 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -937,6 +937,7 @@ static int __devinit aaci_probe_ac97(struct aaci *aaci)
struct snd_ac97 *ac97;
int ret;
+ writel(0, aaci->base + AC97_POWERDOWN);
/*
* Assert AACIRESET for 2us
*/
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/drivers/opl3/opl3_midi.c b/sound/drivers/opl3/opl3_midi.c
index 6e7d09ae0e82..7d722a025d0d 100644
--- a/sound/drivers/opl3/opl3_midi.c
+++ b/sound/drivers/opl3/opl3_midi.c
@@ -29,6 +29,8 @@ extern char snd_opl3_regmap[MAX_OPL2_VOICES][4];
extern int use_internal_drums;
+static void snd_opl3_note_off_unsafe(void *p, int note, int vel,
+ struct snd_midi_channel *chan);
/*
* The next table looks magical, but it certainly is not. Its values have
* been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception
@@ -242,16 +244,20 @@ void snd_opl3_timer_func(unsigned long data)
int again = 0;
int i;
- spin_lock_irqsave(&opl3->sys_timer_lock, flags);
+ spin_lock_irqsave(&opl3->voice_lock, flags);
for (i = 0; i < opl3->max_voices; i++) {
struct snd_opl3_voice *vp = &opl3->voices[i];
if (vp->state > 0 && vp->note_off_check) {
if (vp->note_off == jiffies)
- snd_opl3_note_off(opl3, vp->note, 0, vp->chan);
+ snd_opl3_note_off_unsafe(opl3, vp->note, 0,
+ vp->chan);
else
again++;
}
}
+ spin_unlock_irqrestore(&opl3->voice_lock, flags);
+
+ spin_lock_irqsave(&opl3->sys_timer_lock, flags);
if (again) {
opl3->tlist.expires = jiffies + 1; /* invoke again */
add_timer(&opl3->tlist);
@@ -658,15 +664,14 @@ static void snd_opl3_kill_voice(struct snd_opl3 *opl3, int voice)
/*
* Release a note in response to a midi note off.
*/
-void snd_opl3_note_off(void *p, int note, int vel, struct snd_midi_channel *chan)
+static void snd_opl3_note_off_unsafe(void *p, int note, int vel,
+ struct snd_midi_channel *chan)
{
struct snd_opl3 *opl3;
int voice;
struct snd_opl3_voice *vp;
- unsigned long flags;
-
opl3 = p;
#ifdef DEBUG_MIDI
@@ -674,12 +679,9 @@ void snd_opl3_note_off(void *p, int note, int vel, struct snd_midi_channel *chan
chan->number, chan->midi_program, note);
#endif
- spin_lock_irqsave(&opl3->voice_lock, flags);
-
if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
if (chan->drum_channel && use_internal_drums) {
snd_opl3_drum_switch(opl3, note, vel, 0, chan);
- spin_unlock_irqrestore(&opl3->voice_lock, flags);
return;
}
/* this loop will hopefully kill all extra voices, because
@@ -697,6 +699,16 @@ void snd_opl3_note_off(void *p, int note, int vel, struct snd_midi_channel *chan
snd_opl3_kill_voice(opl3, voice);
}
}
+}
+
+void snd_opl3_note_off(void *p, int note, int vel,
+ struct snd_midi_channel *chan)
+{
+ struct snd_opl3 *opl3 = p;
+ unsigned long flags;
+
+ spin_lock_irqsave(&opl3->voice_lock, flags);
+ snd_opl3_note_off_unsafe(p, note, vel, chan);
spin_unlock_irqrestore(&opl3->voice_lock, flags);
}
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/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/bt87x.c b/sound/pci/bt87x.c
index 24585c6c6d01..4e2b925a94cc 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -808,6 +808,8 @@ static struct pci_device_id snd_bt87x_ids[] = {
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1002, 0x0001, GENERIC),
/* Leadtek Winfast tv 2000xp delux */
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC),
+ /* Pinnacle PCTV */
+ BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x11bd, 0x0012, GENERIC),
/* Voodoo TV 200 */
BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC),
/* Askey Computer Corp. MagicTView'99 */
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_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c
index c8435c9a97f9..9fb60276f5c9 100644
--- a/sound/pci/hda/patch_nvhdmi.c
+++ b/sound/pci/hda/patch_nvhdmi.c
@@ -29,6 +29,9 @@
#include "hda_codec.h"
#include "hda_local.h"
+/* define below to restrict the supported rates and formats */
+/* #define LIMITED_RATE_FMT_SUPPORT */
+
struct nvhdmi_spec {
struct hda_multi_out multiout;
@@ -60,6 +63,22 @@ static struct hda_verb nvhdmi_basic_init[] = {
{} /* terminator */
};
+#ifdef LIMITED_RATE_FMT_SUPPORT
+/* support only the safe format and rate */
+#define SUPPORTED_RATES SNDRV_PCM_RATE_48000
+#define SUPPORTED_MAXBPS 16
+#define SUPPORTED_FORMATS SNDRV_PCM_FMTBIT_S16_LE
+#else
+/* support all rates and formats */
+#define SUPPORTED_RATES \
+ (SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
+ SNDRV_PCM_RATE_192000)
+#define SUPPORTED_MAXBPS 24
+#define SUPPORTED_FORMATS \
+ (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+#endif
+
/*
* Controls
*/
@@ -258,9 +277,9 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch = {
.channels_min = 2,
.channels_max = 8,
.nid = Nv_Master_Convert_nid,
- .rates = SNDRV_PCM_RATE_48000,
- .maxbps = 16,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SUPPORTED_RATES,
+ .maxbps = SUPPORTED_MAXBPS,
+ .formats = SUPPORTED_FORMATS,
.ops = {
.open = nvhdmi_dig_playback_pcm_open,
.close = nvhdmi_dig_playback_pcm_close_8ch,
@@ -273,9 +292,9 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = {
.channels_min = 2,
.channels_max = 2,
.nid = Nv_Master_Convert_nid,
- .rates = SNDRV_PCM_RATE_48000,
- .maxbps = 16,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = SUPPORTED_RATES,
+ .maxbps = SUPPORTED_MAXBPS,
+ .formats = SUPPORTED_FORMATS,
.ops = {
.open = nvhdmi_dig_playback_pcm_open,
.close = nvhdmi_dig_playback_pcm_close_2ch,
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 7810d3dcad83..e01b4b13be97 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -275,7 +275,7 @@ struct alc_spec {
struct snd_kcontrol_new *cap_mixer; /* capture mixer */
unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
- const struct hda_verb *init_verbs[5]; /* initialization verbs
+ const struct hda_verb *init_verbs[10]; /* initialization verbs
* don't forget NULL
* termination!
*/
@@ -1332,15 +1332,20 @@ do_sku:
* when the external headphone out jack is plugged"
*/
if (!spec->autocfg.hp_pins[0]) {
+ hda_nid_t nid;
tmp = (ass >> 11) & 0x3; /* HP to chassis */
if (tmp == 0)
- spec->autocfg.hp_pins[0] = porta;
+ nid = porta;
else if (tmp == 1)
- spec->autocfg.hp_pins[0] = porte;
+ nid = porte;
else if (tmp == 2)
- spec->autocfg.hp_pins[0] = portd;
+ nid = portd;
else
return 1;
+ for (i = 0; i < spec->autocfg.line_outs; i++)
+ if (spec->autocfg.line_out_pins[i] == nid)
+ return 1;
+ spec->autocfg.hp_pins[0] = nid;
}
alc_init_auto_hp(codec);
@@ -1362,7 +1367,7 @@ static void alc_ssid_check(struct hda_codec *codec,
}
/*
- * Fix-up pin default configurations
+ * Fix-up pin default configurations and add default verbs
*/
struct alc_pincfg {
@@ -1370,9 +1375,14 @@ struct alc_pincfg {
u32 val;
};
-static void alc_fix_pincfg(struct hda_codec *codec,
+struct alc_fixup {
+ const struct alc_pincfg *pins;
+ const struct hda_verb *verbs;
+};
+
+static void alc_pick_fixup(struct hda_codec *codec,
const struct snd_pci_quirk *quirk,
- const struct alc_pincfg **pinfix)
+ const struct alc_fixup *fix)
{
const struct alc_pincfg *cfg;
@@ -1380,9 +1390,14 @@ static void alc_fix_pincfg(struct hda_codec *codec,
if (!quirk)
return;
- cfg = pinfix[quirk->value];
- for (; cfg->nid; cfg++)
- snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+ fix += quirk->value;
+ cfg = fix->pins;
+ if (cfg) {
+ for (; cfg->nid; cfg++)
+ snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val);
+ }
+ if (fix->verbs)
+ add_verb(codec->spec, fix->verbs);
}
/*
@@ -4309,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)
@@ -4362,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"
};
@@ -4375,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)
@@ -4406,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)
@@ -4429,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;
@@ -4443,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;
@@ -4470,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;
@@ -5972,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) {
@@ -5992,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;
@@ -9593,11 +9609,13 @@ static struct alc_pincfg alc882_abit_aw9d_pinfix[] = {
{ }
};
-static const struct alc_pincfg *alc882_pin_fixes[] = {
- [PINFIX_ABIT_AW9D_MAX] = alc882_abit_aw9d_pinfix,
+static const struct alc_fixup alc882_fixups[] = {
+ [PINFIX_ABIT_AW9D_MAX] = {
+ .pins = alc882_abit_aw9d_pinfix
+ },
};
-static struct snd_pci_quirk alc882_pinfix_tbl[] = {
+static struct snd_pci_quirk alc882_fixup_tbl[] = {
SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", PINFIX_ABIT_AW9D_MAX),
{}
};
@@ -9869,7 +9887,7 @@ static int patch_alc882(struct hda_codec *codec)
board_config = ALC882_AUTO;
}
- alc_fix_pincfg(codec, alc882_pinfix_tbl, alc882_pin_fixes);
+ alc_pick_fixup(codec, alc882_fixup_tbl, alc882_fixups);
if (board_config == ALC882_AUTO) {
/* automatic parse from the BIOS config */
@@ -10936,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;
@@ -10946,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 */
@@ -12305,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:
@@ -12323,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)
@@ -12331,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;
@@ -12366,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;
@@ -12385,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;
@@ -12842,12 +12851,15 @@ static int patch_alc268(struct hda_codec *codec)
unsigned int wcap = get_wcaps(codec, 0x07);
int i;
+ spec->capsrc_nids = alc268_capsrc_nids;
/* get type */
wcap = get_wcaps_type(wcap);
if (spec->auto_mic ||
wcap != AC_WID_AUD_IN || spec->input_mux->num_items == 1) {
spec->adc_nids = alc268_adc_nids_alt;
spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids_alt);
+ if (spec->auto_mic)
+ fixup_automic_adc(codec);
if (spec->auto_mic || spec->input_mux->num_items == 1)
add_mixer(spec, alc268_capture_nosrc_mixer);
else
@@ -12857,7 +12869,6 @@ static int patch_alc268(struct hda_codec *codec)
spec->num_adc_nids = ARRAY_SIZE(alc268_adc_nids);
add_mixer(spec, alc268_capture_mixer);
}
- spec->capsrc_nids = alc268_capsrc_nids;
/* set default input source */
for (i = 0; i < spec->num_adc_nids; i++)
snd_hda_codec_write_cache(codec, alc268_capsrc_nids[i],
@@ -14235,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));
}
@@ -14357,15 +14366,16 @@ static void alc861_auto_init_multi_out(struct hda_codec *codec)
static void alc861_auto_init_hp_out(struct hda_codec *codec)
{
struct alc_spec *spec = codec->spec;
- hda_nid_t pin;
- pin = spec->autocfg.hp_pins[0];
- if (pin)
- alc861_auto_set_output_and_unmute(codec, pin, PIN_HP,
+ if (spec->autocfg.hp_outs)
+ alc861_auto_set_output_and_unmute(codec,
+ spec->autocfg.hp_pins[0],
+ PIN_HP,
spec->multiout.hp_nid);
- pin = spec->autocfg.speaker_pins[0];
- if (pin)
- alc861_auto_set_output_and_unmute(codec, pin, PIN_OUT,
+ if (spec->autocfg.speaker_outs)
+ alc861_auto_set_output_and_unmute(codec,
+ spec->autocfg.speaker_pins[0],
+ PIN_OUT,
spec->multiout.dac_nids[0]);
}
@@ -15158,7 +15168,7 @@ static struct snd_pci_quirk alc861vd_cfg_tbl[] = {
SND_PCI_QUIRK(0x1019, 0xa88d, "Realtek ALC660 demo", ALC660VD_3ST),
SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_HP),
SND_PCI_QUIRK(0x1043, 0x12e2, "Asus z35m", ALC660VD_3ST),
- SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),
+ /*SND_PCI_QUIRK(0x1043, 0x1339, "Asus G1", ALC660VD_3ST),*/ /* auto */
SND_PCI_QUIRK(0x1043, 0x1633, "Asus V1Sn", ALC660VD_ASUS_V1S),
SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS", ALC660VD_3ST_DIG),
SND_PCI_QUIRK(0x10de, 0x03f0, "Realtek ALC660 demo", ALC660VD_3ST),
@@ -15360,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;
@@ -15377,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)
@@ -15411,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)
@@ -15420,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)
@@ -15439,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;
@@ -15457,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;
@@ -15551,6 +15554,29 @@ static void alc861vd_auto_init(struct hda_codec *codec)
alc_inithook(codec);
}
+enum {
+ ALC660VD_FIX_ASUS_GPIO1
+};
+
+/* reset GPIO1 */
+static const struct hda_verb alc660vd_fix_asus_gpio1_verbs[] = {
+ {0x01, AC_VERB_SET_GPIO_MASK, 0x03},
+ {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+ {0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+ { }
+};
+
+static const struct alc_fixup alc861vd_fixups[] = {
+ [ALC660VD_FIX_ASUS_GPIO1] = {
+ .verbs = alc660vd_fix_asus_gpio1_verbs,
+ },
+};
+
+static struct snd_pci_quirk alc861vd_fixup_tbl[] = {
+ SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
+ {}
+};
+
static int patch_alc861vd(struct hda_codec *codec)
{
struct alc_spec *spec;
@@ -15572,6 +15598,8 @@ static int patch_alc861vd(struct hda_codec *codec)
board_config = ALC861VD_AUTO;
}
+ alc_pick_fixup(codec, alc861vd_fixup_tbl, alc861vd_fixups);
+
if (board_config == ALC861VD_AUTO) {
/* automatic parse from the BIOS config */
err = alc861vd_parse_auto_config(codec);
@@ -17213,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));
}
@@ -17305,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));
}
@@ -17329,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_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
index a9b26828a651..66c0876bf734 100644
--- a/sound/pci/hda/patch_sigmatel.c
+++ b/sound/pci/hda/patch_sigmatel.c
@@ -158,6 +158,7 @@ enum {
STAC_D965_5ST_NO_FP,
STAC_DELL_3ST,
STAC_DELL_BIOS,
+ STAC_927X_VOLKNOB,
STAC_927X_MODELS
};
@@ -907,6 +908,16 @@ static struct hda_verb d965_core_init[] = {
{}
};
+static struct hda_verb dell_3st_core_init[] = {
+ /* don't set delta bit */
+ {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
+ /* unmute node 0x1b */
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+ /* select node 0x03 as DAC */
+ {0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
+ {}
+};
+
static struct hda_verb stac927x_core_init[] = {
/* set master volume and direct control */
{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -915,6 +926,14 @@ static struct hda_verb stac927x_core_init[] = {
{}
};
+static struct hda_verb stac927x_volknob_core_init[] = {
+ /* don't set delta bit */
+ {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
+ /* enable analog pc beep path */
+ {0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
+ {}
+};
+
static struct hda_verb stac9205_core_init[] = {
/* set master volume and direct control */
{ 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
@@ -1999,6 +2018,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = {
[STAC_D965_5ST_NO_FP] = d965_5st_no_fp_pin_configs,
[STAC_DELL_3ST] = dell_3st_pin_configs,
[STAC_DELL_BIOS] = NULL,
+ [STAC_927X_VOLKNOB] = NULL,
};
static const char *stac927x_models[STAC_927X_MODELS] = {
@@ -2010,6 +2030,7 @@ static const char *stac927x_models[STAC_927X_MODELS] = {
[STAC_D965_5ST_NO_FP] = "5stack-no-fp",
[STAC_DELL_3ST] = "dell-3stack",
[STAC_DELL_BIOS] = "dell-bios",
+ [STAC_927X_VOLKNOB] = "volknob",
};
static struct snd_pci_quirk stac927x_cfg_tbl[] = {
@@ -2045,6 +2066,8 @@ static struct snd_pci_quirk stac927x_cfg_tbl[] = {
"Intel D965", STAC_D965_5ST),
SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500,
"Intel D965", STAC_D965_5ST),
+ /* volume-knob fixes */
+ SND_PCI_QUIRK_VENDOR(0x10cf, "FSC", STAC_927X_VOLKNOB),
{} /* terminator */
};
@@ -5612,10 +5635,14 @@ static int patch_stac927x(struct hda_codec *codec)
spec->dmic_nids = stac927x_dmic_nids;
spec->num_dmics = STAC927X_NUM_DMICS;
- spec->init = d965_core_init;
+ spec->init = dell_3st_core_init;
spec->dmux_nids = stac927x_dmux_nids;
spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids);
break;
+ case STAC_927X_VOLKNOB:
+ spec->num_dmics = 0;
+ spec->init = stac927x_volknob_core_init;
+ break;
default:
spec->num_dmics = 0;
spec->init = stac927x_core_init;
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/amp.c b/sound/pci/ice1712/amp.c
index 37564300b50d..6da21a2bcade 100644
--- a/sound/pci/ice1712/amp.c
+++ b/sound/pci/ice1712/amp.c
@@ -52,11 +52,13 @@ static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice)
/* only use basic functionality for now */
- ice->num_total_dacs = 2; /* only PSDOUT0 is connected */
+ /* VT1616 6ch codec connected to PSDOUT0 using packed mode */
+ ice->num_total_dacs = 6;
ice->num_total_adcs = 2;
- /* Chaintech AV-710 has another codecs, which need initialization */
- /* initialize WM8728 codec */
+ /* Chaintech AV-710 has another WM8728 codec connected to PSDOUT4
+ (shared with the SPDIF output). Mixer control for this codec
+ is not yet supported. */
if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AV710) {
for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2)
wm_put(ice, wm_inits[i], wm_inits[i+1]);
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index cecf1ffeeaaa..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);
@@ -2259,7 +2269,7 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol,
}
static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Multi Track Peak",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.info = snd_ice1712_pro_peak_info,
@@ -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 af6e00148621..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));
@@ -648,19 +672,25 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate,
(inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) {
/* running? we cannot change the rate now... */
spin_unlock_irqrestore(&ice->reg_lock, flags);
- return -EBUSY;
+ 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;
}
@@ -1294,7 +1328,7 @@ static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ice->pci),
- 64*1024, 64*1024);
+ 256*1024, 256*1024);
ice->pcm = pcm;
@@ -1408,7 +1442,7 @@ static int __devinit snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device)
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(ice->pci),
- 64*1024, 64*1024);
+ 256*1024, 256*1024);
ice->pcm_ds = pcm;
@@ -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;
@@ -2110,7 +2160,7 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol,
}
static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
.name = "Multi Track Peak",
.access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
.info = snd_vt1724_pro_peak_info,
@@ -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..4bed9633a4cd 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -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/pci/via82xx.c b/sound/pci/via82xx.c
index acfa4760da49..91683a349035 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1626,7 +1626,7 @@ static int snd_via8233_dxs_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct via82xx *chip = snd_kcontrol_chip(kcontrol);
- unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id);
+ unsigned int idx = kcontrol->id.subdevice;
ucontrol->value.integer.value[0] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][0];
ucontrol->value.integer.value[1] = VIA_DXS_MAX_VOLUME - chip->playback_volume[idx][1];
@@ -1646,7 +1646,7 @@ static int snd_via8233_dxs_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct via82xx *chip = snd_kcontrol_chip(kcontrol);
- unsigned int idx = snd_ctl_get_ioff(kcontrol, &ucontrol->id);
+ unsigned int idx = kcontrol->id.subdevice;
unsigned long port = chip->port + 0x10 * idx;
unsigned char val;
int i, change = 0;
@@ -1705,11 +1705,12 @@ static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata =
};
static struct snd_kcontrol_new snd_via8233_dxs_volume_control __devinitdata = {
- .name = "VIA DXS Playback Volume",
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+ .device = 0,
+ /* .subdevice set later */
+ .name = "PCM Playback Volume",
.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ),
- .count = 4,
.info = snd_via8233_dxs_volume_info,
.get = snd_via8233_dxs_volume_get,
.put = snd_via8233_dxs_volume_put,
@@ -1936,10 +1937,18 @@ static int __devinit snd_via8233_init_misc(struct via82xx *chip)
}
else /* Using DXS when PCM emulation is enabled is really weird */
{
- /* Standalone DXS controls */
- err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_dxs_volume_control, chip));
- if (err < 0)
- return err;
+ for (i = 0; i < 4; ++i) {
+ struct snd_kcontrol *kctl;
+
+ kctl = snd_ctl_new1(
+ &snd_via8233_dxs_volume_control, chip);
+ if (!kctl)
+ return -ENOMEM;
+ kctl->id.subdevice = i;
+ err = snd_ctl_add(chip->card, kctl);
+ if (err < 0)
+ return err;
+ }
}
}
/* select spdif data slot 10/11 */
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..fab01c991828 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,7 @@ 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_TWL4030 if TWL4030_CORE
select SND_SOC_UDA134X
select SND_SOC_UDA1380 if I2C
@@ -36,6 +38,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 +99,9 @@ config SND_SOC_AK4535
config SND_SOC_AK4642
tristate
+config SND_SOC_AK4671
+ tristate
+
# Cirrus Logic CS4270 Codec
config SND_SOC_CS4270
tristate
@@ -160,6 +166,9 @@ config SND_SOC_WM8523
config SND_SOC_WM8580
tristate
+config SND_SOC_WM8711
+ tristate
+
config SND_SOC_WM8728
tristate
@@ -220,3 +229,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..2f14391b96f9 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
@@ -24,6 +25,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 +49,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 +59,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
@@ -74,6 +78,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 +102,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/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
new file mode 100644
index 000000000000..0a6e7b4ace60
--- /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]);
+}
+
+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..6a794f16cee9
--- /dev/null
+++ b/sound/soc/codecs/tpa6130a2.h
@@ -0,0 +1,62 @@
+/*
+ * 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);
+extern void tpa6130a2_power(int power);
+
+#endif /* __TPA6130A2_H__ */
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 3ff0373dff89..72abc5a6d8d8 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -579,7 +579,7 @@ static const struct snd_kcontrol_new wm8350_left_capt_mixer_controls[] = {
SOC_DAPM_SINGLE_TLV("L3 Capture Volume",
WM8350_INPUT_MIXER_VOLUME_L, 9, 7, 0, out_mix_tlv),
SOC_DAPM_SINGLE("PGA Capture Switch",
- WM8350_LEFT_INPUT_VOLUME, 14, 1, 0),
+ WM8350_LEFT_INPUT_VOLUME, 14, 1, 1),
};
/* Right Input Mixer */
@@ -589,7 +589,7 @@ static const struct snd_kcontrol_new wm8350_right_capt_mixer_controls[] = {
SOC_DAPM_SINGLE_TLV("L3 Capture Volume",
WM8350_INPUT_MIXER_VOLUME_R, 13, 7, 0, out_mix_tlv),
SOC_DAPM_SINGLE("PGA Capture Switch",
- WM8350_RIGHT_INPUT_VOLUME, 14, 1, 0),
+ WM8350_RIGHT_INPUT_VOLUME, 14, 1, 1),
};
/* Left Mic Mixer */
@@ -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;
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index b9ef4d915221..9cb8e50f0fbb 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;
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/wm8580.c b/sound/soc/codecs/wm8580.c
index 6bded8c78150..3be5c0b2552c 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;
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
new file mode 100644
index 000000000000..90ec8c58e2f4
--- /dev/null
+++ b/sound/soc/codecs/wm8711.c
@@ -0,0 +1,659 @@
+/*
+ * 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;
+}
+
+#ifdef CONFIG_PM
+static int wm8711_spi_suspend(struct spi_device *spi, pm_message_t msg)
+{
+ return snd_soc_suspend_device(&spi->dev);
+}
+
+static int wm8711_spi_resume(struct spi_device *spi)
+{
+ return snd_soc_resume_device(&spi->dev);
+}
+#else
+#define wm8711_spi_suspend NULL
+#define wm8711_spi_resume NULL
+#endif
+
+static struct spi_driver wm8711_spi_driver = {
+ .driver = {
+ .name = "wm8711",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = wm8711_spi_probe,
+ .suspend = wm8711_spi_suspend,
+ .resume = wm8711_spi_resume,
+ .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/wm8753.c b/sound/soc/codecs/wm8753.c
index 5ad677ce80da..9b27efb052fe 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;
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 5e9c855c0036..882604ef768c 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);
}
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index da97aae475a2..1685cfb993c6 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;
@@ -790,7 +790,7 @@ static int wm8940_register(struct wm8940_priv *wm8940,
codec->reg_cache = &wm8940->reg_cache;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, control);
- if (ret == 0) {
+ if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index f59703be61c8..416fb3c17018 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;
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/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/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/imx/mxc-ssi.c b/sound/soc/imx/mxc-ssi.c
index 3806ff2c0cd4..ccdefe60e752 100644
--- a/sound/soc/imx/mxc-ssi.c
+++ b/sound/soc/imx/mxc-ssi.c
@@ -397,14 +397,6 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai,
break;
}
- /* sync */
- if (!(fmt & SND_SOC_DAIFMT_ASYNC))
- scr |= SSI_SCR_SYN;
-
- /* tdm - only for stereo atm */
- if (fmt & SND_SOC_DAIFMT_TDM)
- scr |= SSI_SCR_NET;
-
if (cpu_dai->id == IMX_DAI_SSI0 || cpu_dai->id == IMX_DAI_SSI2) {
SSI1_STCR = stcr;
SSI1_SRCR = srcr;
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..c9b794843a70 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -137,7 +137,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 +153,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 +203,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 +219,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..11c45a37c631 100644
--- a/sound/soc/s3c24xx/s3c-i2s-v2.c
+++ b/sound/soc/s3c24xx/s3c-i2s-v2.c
@@ -312,12 +312,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 +470,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 +654,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/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c
index 3c06c401d0fb..43fb253a3429 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.c
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.c
@@ -99,6 +99,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 +124,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..1dec9d21c55e 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -1254,21 +1254,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 +1296,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 +2213,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 +2269,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 f79711b9fa5b..d2af872e4771 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -524,7 +524,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget)
/* connected jack or spk ? */
if (widget->id == snd_soc_dapm_hp || widget->id == snd_soc_dapm_spk ||
- widget->id == snd_soc_dapm_line)
+ (widget->id == snd_soc_dapm_line && !list_empty(&widget->sources)))
return 1;
}
@@ -573,7 +573,8 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget)
return 1;
/* connected jack ? */
- if (widget->id == snd_soc_dapm_mic || widget->id == snd_soc_dapm_line)
+ if (widget->id == snd_soc_dapm_mic ||
+ (widget->id == snd_soc_dapm_line && !list_empty(&widget->sinks)))
return 1;
}
@@ -718,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;
@@ -1137,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",
@@ -1144,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",
@@ -1191,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;
@@ -1201,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 */
@@ -1386,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 */
@@ -1413,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);
@@ -1513,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,
@@ -1751,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;
@@ -1771,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);
@@ -1793,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
@@ -1850,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;
@@ -1868,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);
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-timechart.txt b/tools/perf/Documentation/perf-timechart.txt
index 1c2ed3090cce..a7910099d6fd 100644
--- a/tools/perf/Documentation/perf-timechart.txt
+++ b/tools/perf/Documentation/perf-timechart.txt
@@ -31,6 +31,9 @@ OPTIONS
-w::
--width=::
Select the width of the SVG file (default: 1000)
+-p::
+--power-only::
+ Only output the CPU power section of the diagram
SEE ALSO
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index b5f1953b6144..742a32eee8fc 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -157,11 +157,18 @@ uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
uname_P := $(shell sh -c 'uname -p 2>/dev/null || echo not')
uname_V := $(shell sh -c 'uname -v 2>/dev/null || echo not')
-# If we're on a 64-bit kernel, use -m64
-ifndef NO_64BIT
- ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
- M64 := -m64
- endif
+#
+# Add -m32 for cross-builds:
+#
+ifdef NO_64BIT
+ MBITS := -m32
+else
+ #
+ # If we're on a 64-bit kernel, use -m64:
+ #
+ ifneq ($(patsubst %64,%,$(uname_M)),$(uname_M))
+ MBITS := -m64
+ endif
endif
# CFLAGS and LDFLAGS are for the users to override from the command line.
@@ -194,7 +201,7 @@ EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wold-style-definition
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wstrict-prototypes
EXTRA_WARNINGS := $(EXTRA_WARNINGS) -Wdeclaration-after-statement
-CFLAGS = $(M64) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS)
+CFLAGS = $(MBITS) -ggdb3 -Wall -Wextra -std=gnu99 -Werror -O6 -fstack-protector-all -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS)
LDFLAGS = -lpthread -lrt -lelf -lm
ALL_CFLAGS = $(CFLAGS)
ALL_LDFLAGS = $(LDFLAGS)
@@ -416,7 +423,7 @@ ifeq ($(uname_S),Darwin)
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);
+ msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
endif
ifdef NO_DEMANGLE
@@ -728,7 +735,7 @@ $(BUILT_INS): perf$X
common-cmds.h: util/generate-cmdlist.sh command-list.txt
common-cmds.h: $(wildcard Documentation/perf-*.txt)
- $(QUIET_GEN)util/generate-cmdlist.sh > $@+ && mv $@+ $@
+ $(QUIET_GEN). util/generate-cmdlist.sh > $@+ && mv $@+ $@
$(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
$(QUIET_GEN)$(RM) $@ $@+ && \
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index a5a050af8e7d..3eeef339c787 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -41,6 +41,7 @@ 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;
@@ -184,6 +185,9 @@ static void sig_handler(int sig)
static void sig_atexit(void)
{
+ if (child_pid != -1)
+ kill(child_pid, SIGTERM);
+
if (signr == -1)
return;
@@ -610,6 +614,8 @@ static int __cmd_record(int argc, const char **argv)
exit(-1);
}
}
+
+ child_pid = pid;
}
if (realtime_prio) {
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c
index ea9c15c0cdfe..ce2d5be4f30e 100644
--- a/tools/perf/builtin-sched.c
+++ b/tools/perf/builtin-sched.c
@@ -1287,7 +1287,7 @@ static struct sort_dimension *available_sorts[] = {
static LIST_HEAD(sort_list);
-static int sort_dimension__add(char *tok, struct list_head *list)
+static int sort_dimension__add(const char *tok, struct list_head *list)
{
int i;
@@ -1917,7 +1917,7 @@ static void setup_sorting(void)
free(str);
- sort_dimension__add((char *)"pid", &cmp_pid);
+ sort_dimension__add("pid", &cmp_pid);
}
static const char *record_args[] = {
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index e5f6ece65a13..3db31e7bf173 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -69,7 +69,8 @@ static int run_idx = 0;
static int run_count = 1;
static int inherit = 1;
static int scale = 1;
-static int target_pid = -1;
+static pid_t target_pid = -1;
+static pid_t child_pid = -1;
static int null_run = 0;
static int fd[MAX_NR_CPUS][MAX_COUNTERS];
@@ -285,6 +286,8 @@ static int run_perf_stat(int argc __used, const char **argv)
exit(-1);
}
+ child_pid = pid;
+
/*
* Wait for the child to be ready to exec.
*/
@@ -433,6 +436,9 @@ static void skip_signal(int signo)
static void sig_atexit(void)
{
+ if (child_pid != -1)
+ kill(child_pid, SIGTERM);
+
if (signr == -1)
return;
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 4405681b3134..702d8fe58fbc 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -46,6 +46,8 @@ static u64 turbo_frequency;
static u64 first_time, last_time;
+static int power_only;
+
static struct perf_header *header;
@@ -547,7 +549,7 @@ static void end_sample_processing(void)
u64 cpu;
struct power_event *pwr;
- for (cpu = 0; cpu < numcpus; cpu++) {
+ for (cpu = 0; cpu <= numcpus; cpu++) {
pwr = malloc(sizeof(struct power_event));
if (!pwr)
return;
@@ -871,7 +873,7 @@ static int determine_display_tasks(u64 threshold)
/* no exit marker, task kept running to the end */
if (p->end_time == 0)
p->end_time = last_time;
- if (p->total_time >= threshold)
+ if (p->total_time >= threshold && !power_only)
p->display = 1;
c = p->all;
@@ -882,7 +884,7 @@ static int determine_display_tasks(u64 threshold)
if (c->start_time == 1)
c->start_time = first_time;
- if (c->total_time >= threshold) {
+ if (c->total_time >= threshold && !power_only) {
c->display = 1;
count++;
}
@@ -1134,6 +1136,8 @@ static const struct option options[] = {
"output file name"),
OPT_INTEGER('w', "width", &svg_page_width,
"page width"),
+ OPT_BOOLEAN('p', "power-only", &power_only,
+ "output power data only"),
OPT_END()
};
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index 1ca88896eee4..37512e936235 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -782,6 +782,7 @@ static const char *skip_symbols[] = {
"exit_idle",
"mwait_idle",
"mwait_idle_with_hints",
+ "poll_idle",
"ppc64_runlatch_off",
"pseries_dedicated_idle_sleep",
NULL
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index e9d256e2f47d..0c5e4f72f2ba 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -219,10 +219,6 @@ remap:
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;
@@ -237,7 +233,6 @@ more:
size = event->header.size;
-
if (!size || process_event(event, offset, head) < 0) {
/*
@@ -290,7 +285,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __used)
usage_with_options(annotate_usage, options);
}
-
setup_pager();
return __cmd_trace();
diff --git a/tools/perf/design.txt b/tools/perf/design.txt
index f1946d107b10..fdd42a824c98 100644
--- a/tools/perf/design.txt
+++ b/tools/perf/design.txt
@@ -455,3 +455,6 @@ will need at least this:
If your architecture does have hardware capabilities, you can override the
weak stub hw_perf_event_init() to register hardware counters.
+
+Architectures that have d-cache aliassing issues, such as Sparc and ARM,
+should select PERF_USE_VMALLOC in order to avoid these for perf mmap().
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 87c424de79ee..8cfb48cbbea0 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -691,7 +691,10 @@ static void store_event_type(const char *orgname)
FILE *file;
int id;
- sprintf(filename, "/sys/kernel/debug/tracing/events/%s/id", orgname);
+ sprintf(filename, "%s/", debugfs_path);
+ strncat(filename, orgname, strlen(orgname));
+ strcat(filename, "/id");
+
c = strchr(filename, ':');
if (c)
*c = '/';
diff --git a/tools/perf/util/svghelper.c b/tools/perf/util/svghelper.c
index a778fd0f4ae4..856655d8b0b8 100644
--- a/tools/perf/util/svghelper.c
+++ b/tools/perf/util/svghelper.c
@@ -28,7 +28,7 @@ static u64 turbo_frequency, max_freq;
int svg_page_width = 1000;
-#define MIN_TEXT_SIZE 0.001
+#define MIN_TEXT_SIZE 0.01
static u64 total_height;
static FILE *svgfile;
@@ -217,6 +217,18 @@ static char *cpu_model(void)
}
fclose(file);
}
+
+ /* CPU type */
+ file = fopen("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies", "r");
+ if (file) {
+ while (fgets(buf, 255, file)) {
+ unsigned int freq;
+ freq = strtoull(buf, NULL, 10);
+ if (freq > max_freq)
+ max_freq = freq;
+ }
+ fclose(file);
+ }
return cpu_m;
}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 559fb06210f5..47ea0609a760 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -324,8 +324,7 @@ static inline int elf_sym__is_function(const GElf_Sym *sym)
{
return elf_sym__type(sym) == STT_FUNC &&
sym->st_name != 0 &&
- sym->st_shndx != SHN_UNDEF &&
- sym->st_size != 0;
+ sym->st_shndx != SHN_UNDEF;
}
static inline int elf_sym__is_label(const GElf_Sym *sym)
diff --git a/tools/perf/util/trace-event-parse.c b/tools/perf/util/trace-event-parse.c
index f6a8437141c8..55c9659a56e2 100644
--- a/tools/perf/util/trace-event-parse.c
+++ b/tools/perf/util/trace-event-parse.c
@@ -618,7 +618,7 @@ static int test_type(enum event_type type, enum event_type expect)
}
static int test_type_token(enum event_type type, char *token,
- enum event_type expect, char *expect_tok)
+ enum event_type expect, const char *expect_tok)
{
if (type != expect) {
die("Error: expected type %d but read %d",
@@ -650,7 +650,7 @@ static int read_expect_type(enum event_type expect, char **tok)
return __read_expect_type(expect, tok, 1);
}
-static int __read_expected(enum event_type expect, char *str, int newline_ok)
+static int __read_expected(enum event_type expect, const char *str, int newline_ok)
{
enum event_type type;
char *token;
@@ -668,12 +668,12 @@ static int __read_expected(enum event_type expect, char *str, int newline_ok)
return 0;
}
-static int read_expected(enum event_type expect, char *str)
+static int read_expected(enum event_type expect, const char *str)
{
return __read_expected(expect, str, 1);
}
-static int read_expected_item(enum event_type expect, char *str)
+static int read_expected_item(enum event_type expect, const char *str)
{
return __read_expected(expect, str, 0);
}
@@ -1968,10 +1968,11 @@ static const struct flag flags[] = {
{ "NET_TX_SOFTIRQ", 2 },
{ "NET_RX_SOFTIRQ", 3 },
{ "BLOCK_SOFTIRQ", 4 },
- { "TASKLET_SOFTIRQ", 5 },
- { "SCHED_SOFTIRQ", 6 },
- { "HRTIMER_SOFTIRQ", 7 },
- { "RCU_SOFTIRQ", 8 },
+ { "BLOCK_IOPOLL_SOFTIRQ", 5 },
+ { "TASKLET_SOFTIRQ", 6 },
+ { "SCHED_SOFTIRQ", 7 },
+ { "HRTIMER_SOFTIRQ", 8 },
+ { "RCU_SOFTIRQ", 9 },
{ "HRTIMER_NORESTART", 0 },
{ "HRTIMER_RESTART", 1 },
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 e79c54034bcd..c0a929fe33ce 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)) {
@@ -850,6 +244,19 @@ static void kvm_mmu_notifier_invalidate_page(struct mmu_notifier *mn,
}
+static void kvm_mmu_notifier_change_pte(struct mmu_notifier *mn,
+ struct mm_struct *mm,
+ unsigned long address,
+ pte_t pte)
+{
+ struct kvm *kvm = mmu_notifier_to_kvm(mn);
+
+ spin_lock(&kvm->mmu_lock);
+ kvm->mmu_notifier_seq++;
+ kvm_set_spte_hva(kvm, address, pte);
+ spin_unlock(&kvm->mmu_lock);
+}
+
static void kvm_mmu_notifier_invalidate_range_start(struct mmu_notifier *mn,
struct mm_struct *mm,
unsigned long start,
@@ -929,12 +336,14 @@ static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {
.invalidate_range_start = kvm_mmu_notifier_invalidate_range_start,
.invalidate_range_end = kvm_mmu_notifier_invalidate_range_end,
.clear_flush_young = kvm_mmu_notifier_clear_flush_young,
+ .change_pte = kvm_mmu_notifier_change_pte,
.release = kvm_mmu_notifier_release,
};
#endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */
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;
@@ -942,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);
@@ -959,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
@@ -991,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);
}
/*
@@ -1049,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);
}
@@ -1675,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);
@@ -1814,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)
{
@@ -2154,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;
@@ -2291,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;
@@ -2428,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)
@@ -2445,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:
@@ -2652,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;
}
@@ -2735,7 +2019,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;
@@ -2783,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: